gpxpy
gpxpy is a Python library for parsing, manipulating, and creating GPX (GPS eXchange Format) files. GPX is an XML-based file format commonly used for GPS tracks, routes, and waypoints. The library supports both GPX 1.0 and 1.1 versions. It is currently at version 1.6.2 and is actively maintained, with regular releases and contributions.
Warnings
- gotcha The `gpxpy.parse()` function expects a file-like object, not a file path string. Passing a path directly can lead to `xml.etree.ElementTree.ParseError: not well-formed (invalid token)` errors.
- gotcha The `gpxpy` object model is not 100% equivalent to the GPX XML schema, particularly between GPX 1.0 and 1.1. Attributes like 'speed' (present in GPX 1.0 but removed in 1.1) might be lost or handled inconsistently if you parse one version and serialize to another without explicit management (e.g., using extensions or forcing version).
- gotcha When calculating statistics like `max_speed` or `uphill/downhill`, `gpxpy` applies heuristics to filter out common GPS errors (e.g., removing top 5% of speeds or points with non-standard distances). The raw data might differ.
- gotcha GPX extensions (custom XML elements within the GPX structure) are preserved as `ElementTree` DOM objects. However, they might be ignored when serializing a GPX 1.1 object to a GPX 1.0 file, and there have been reports of extension data being lost or not properly outputted during read/write operations if not handled carefully.
- gotcha Generated GPX XML, while always a valid XML document, may not always be a strictly valid GPX document if certain string fields (e.g., `gpx.email`) do not conform to the expected regex patterns defined by the GPX schema.
Install
-
pip install gpxpy
Imports
- gpxpy
import gpxpy
- gpxpy.gpx
from gpxpy import GPX, GPXTrack, GPXTrackSegment, GPXTrackPoint
import gpxpy.gpx
Quickstart
import gpxpy
import gpxpy.gpx
import os
# Create a dummy GPX file for demonstration
dummy_gpx_content = """
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" creator="gpxpy" version="1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<trk>
<name>Example Track</name>
<trkseg>
<trkpt lat="48.123" lon="11.456">
<ele>500.0</ele>
<time>2023-01-01T10:00:00Z</time>
</trkpt>
<trkpt lat="48.124" lon="11.457">
<ele>505.0</ele>
<time>2023-01-01T10:01:00Z</time>
</trkpt>
</trkseg>
</trk>
<wpt lat="48.125" lon="11.458">
<name>Example Waypoint</name>
</wpt>
</gpx>
"""
dummy_gpx_filename = "example.gpx"
with open(dummy_gpx_filename, "w") as f:
f.write(dummy_gpx_content)
try:
# Parsing an existing GPX file
with open(dummy_gpx_filename, 'r') as gpx_file:
gpx = gpxpy.parse(gpx_file)
print(f"GPX parsed successfully. Version: {gpx.version}")
for track_idx, track in enumerate(gpx.tracks):
print(f" Track {track_idx + 1}: {track.name or 'Unnamed Track'}")
for segment_idx, segment in enumerate(track.segments):
print(f" Segment {segment_idx + 1}: {len(segment.points)} points")
for point_idx, point in enumerate(segment.points):
print(f" Point {point_idx + 1}: Lat={point.latitude}, Lon={point.longitude}, Ele={point.elevation}, Time={point.time}")
for wpt_idx, waypoint in enumerate(gpx.waypoints):
print(f" Waypoint {wpt_idx + 1}: {waypoint.name or 'Unnamed Waypoint'} at Lat={waypoint.latitude}, Lon={waypoint.longitude}")
# Getting some statistics
if gpx.has_points():
moving_data = gpx.get_moving_data()
print(f"Total distance: {gpx.length_3d()/1000:.2f} km")
print(f"Max speed: {moving_data.max_speed * 3.6:.2f} km/h (filtered)")
print(f"Total uphill: {gpx.get_uphill_downhill().uphill:.2f} m")
print(f"Total downhill: {gpx.get_uphill_downhill().downhill:.2f} m")
# Creating a new GPX file programmatically
new_gpx = gpxpy.gpx.GPX()
new_track = gpxpy.gpx.GPXTrack()
new_gpx.tracks.append(new_track)
new_segment = gpxpy.gpx.GPXTrackSegment()
new_track.segments.append(new_segment)
new_segment.points.append(gpxpy.gpx.GPXTrackPoint(48.2, 11.5, elevation=550, time='2023-01-01T11:00:00Z'))
new_segment.points.append(gpxpy.gpx.GPXTrackPoint(48.21, 11.51, elevation=560, time='2023-01-01T11:05:00Z'))
print("\nGenerated new GPX content:")
print(new_gpx.to_xml())
finally:
# Clean up the dummy file
if os.path.exists(dummy_gpx_filename):
os.remove(dummy_gpx_filename)