GPX is more and more becoming the lingua franca for storing cycling rides. Basically it is a list of points, called track points, with satellite positions (latitude and longitude) decorated with extra information (elevation, heartrate, cadence, power or temperature). A track (<trk>), has one or more segments (<trkseg>) with a list of trackpoints (<trkpt>)
<trk> <name>Track Name</name> <trkseg> <trkpt lat="50.653007542714477" lon="5.558940963819623" />Lots of track point...
<trkpt lat="50.653007542714477" lon="5.558940963819623" /> </trkseg> </trk>Sometimes elevation is also included for every trackpoint:
<trk> <name>Track Name</name> <trkseg> <trkpt lat="50.653007542714477" lon="5.558940963819623" > <ele>60.0</ele> </trkpt>Lots of track point...
<trkpt lat="50.653007542714477" lon="5.558940963819623" > <ele>60.0</ele> </trkpt> </trkseg> </trk>Those GPX files can be used as tracks that you can follow. You can copy those file to the New File directory on your Garmin and you can select them to follow. If
<ele> … </ele>elements are included you will see how the height evolves in front of you.
If you download the GPX file from a ride you rode with a bike computer that registers cadence and heartrate, the file will look like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<gpx creator="StravaGPX" version="1.1" xmlns="http://www.topografix.com/GPX/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 http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"> | |
<metadata> | |
<time>2014-06-15T15:45:39Z</time> | |
</metadata> | |
<trk> | |
<name>Example GPX file from Strava</name> | |
<trkseg> | |
<trkpt lat="50.8758450" lon="4.6710150"> | |
<ele>60.0</ele> | |
<time>2014-06-15T15:45:39Z</time> | |
<extensions> | |
<gpxtpx:TrackPointExtension> | |
<gpxtpx:atemp>25</gpxtpx:atemp> | |
<gpxtpx:hr>107</gpxtpx:hr> | |
<gpxtpx:cad>65</gpxtpx:cad> | |
</gpxtpx:TrackPointExtension> | |
</extensions> | |
</trkpt> | |
... Lots of track points | |
</trkseg> | |
</trk> | |
</gpx> |
The elevation element is part of the standard GPS specification as defined by the XML schema provided hre: http://www.topografix.com/gpx.asp The heartrate and cadence are stored using trackpoint extensions as specfied here: http://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd
Here is a simple Python example to parse a Strava GPX file with extensions using minidom:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from xml.dom import minidom | |
import datetime | |
tracks = {} | |
def parseTrack(trk): | |
name = trk.getElementsByTagName('name')[0].firstChild.data | |
if not name in tracks: | |
tracks[name] = [] | |
for trkseg in trk.getElementsByTagName('trkseg'): | |
for trkpt in trkseg.getElementsByTagName('trkpt'): | |
lat = float(trkpt.getAttribute('lat')) | |
lon = float(trkpt.getAttribute('lon')) | |
ele = float(trkpt.getElementsByTagName('ele')[0].firstChild.data) | |
rfc3339 = trkpt.getElementsByTagName('time')[0].firstChild.data | |
try: | |
t = datetime.datetime.strptime(rfc3339, '%Y-%m-%dT%H:%M:%S.%fZ') | |
except ValueError: | |
t = datetime.datetime.strptime(rfc3339, '%Y-%m-%dT%H:%M:%SZ') | |
extensions = trkpt.getElementsByTagName('extensions')[0] | |
trkPtExtension = extensions.getElementsByTagName('gpxtpx:TrackPointExtension')[0] | |
if trkPtExtension: | |
hr = int(trkPtExtension.getElementsByTagName('gpxtpx:hr')[0].firstChild.data) | |
cad = int(trkPtExtension.getElementsByTagName('gpxtpx:cad')[0].firstChild.data) | |
if trkPtExtension.getElementsByTagName('gpxtpx:atemp'): | |
atemp = int(trkPtExtension.getElementsByTagName('gpxtpx:atemp')[0].firstChild.data) | |
tracks[name].append({'lat':lat, 'lon':lon, 'ele':ele, 'time':t, 'hr':hr, 'cad':cad, 'atemp':atemp}) | |
doc = minidom.parse('ride.gpx') | |
doc.normalize() | |
gpx = doc.documentElement | |
for node in gpx.getElementsByTagName('trk'): | |
parseTrack(node) | |
print tracks |