各地网友 GPS art 作品

GPX 是 GPS exchange 文件格式,被运动跟踪类的软硬件广泛使用。本篇做一个快速指南,帮助大家玩转 GPX。

动机

很多刚入门耐力运动的朋友,会有打卡需求。好不容易走了几十公里,在地图上画条线出来,放到朋友圈特别有面子。不过,只要跑得够多,就一定会遇到记录不完美的状况。

比如我第一次穿越港岛,走了差不多 25 K,结果在离终点 200m 的地方,手机停电了,于是打卡失败。

第一次穿越港岛,手机没电

另外一种情况,就是忘记停表/ 关App 了,结果关闭的时候,一瞬间飞了回去,在地图上划出一道长长直线。这个状况在用 Trail Watch 的时候,经常出现。

忘记关表的情况

第三类翻车,就是中途停下来休息,结果再出发时,别人开了表而自己忘了…… 等到想起来的时候,又是一条飞线,把最重要的山头给略过了。

休息后忘记开表的情况

第四类翻车,是由于各种意外,中途停表了(Apple Watch 很容易出现),结果本来一段 20K 的记录变成两段 10K 的。

出现以上情况,就问你难不难受?

所以,我们要学习 GPX。

基础

数据导出

Strava 上可以方便地导出 GPX 文件。

Strava 数据导出位置

Strava 还可以使用 API  来获取数据,对于开发者很有好。

Python 用户可以使用一个叫做 stravalib 的库,虽然上手方便,但不推荐。有一些主要问题:

该库一个 activity 一个 HTTP request,很快会用完 quota。像我两年的记录,就无法在一天内获取完。

由于 Strava 的升级,出现了一些新的 activity 类型,但该库的维护并不是很及时,loop 中遇到数据错误的时候,可能会前功尽弃。

推荐使用 request,直接调用 HTTP endpoint,一行可以搞定。

r = requests.get(
    'https://www.strava.com/api/v3/athlete/activities',
    params={
        'page': 1,
        'per_page': 100,
    },
    headers={
        'Authorization': 'Bearer {}'.format(access_token),
    }
)

一次 100 条,几秒钟就可以把一个人的记录给拉完了。

数据导入

还是以 Strava 为例。

先 upload activity。

在这里选择文件。上传 GPX 即可。

GPX

GPX 本质上是一种 XML 格式的文件。

它有三个层级,上一层可以包含多个下层元素:

Track

Segment

Point

我们最关心的是 Point。

Point 的必要数据为:

lat, lon, ele

time

根据这些,可以推算时间、距离、爬升、速度等,基本的运动参数就有了。

另外,还有一些非标准的拓展数据,通常会被跑表记录,比如 Garmin 的表会录入这些数据:

Temperature

Heart rate

Cadence

一个实际的 GPX 文件,长成这样。它是纯文本文件,所以可以用任何编辑器来编辑。

GPX 文件样例

裁剪

最简单的一个操作,在 Strava 上默认支持。如果是活动的首尾想去掉,那就非常简单了。

Strava 裁剪活动示例

如果想去掉的部分,位于活动的中间,那就只能约化(reduction)一下这个问题:

Duplicate 该活动

分别裁剪第一段和第二段

转化为一个拼接问题

拼接

如果知道 GPX 文件的原理,自然拼接就很简单。

拿文本编辑器打开两个 GPX 文件。

其中一组 <trkpt ...> ...</trkpt> 中间的内容,就是一个记录点。所以你要做的,就是把一个文件中的这些  <trkpt ...> ...</trkpt> ,全部都拷贝到另一个文件中  <trkpt ...> ...</trkpt>  的后面即可。

GPX 文件样例

创造

这是用来解决手表完全停电的情况。可能你只能根据自己对路线的理解,把没记录的部分给画出来,再和已经记录的部分进行拼接。

画地图有很多工具,我个人比较喜欢的是:https://geojson.io/[1]

https://geojson.io/

GeoJSON 是一个流行的地理信息格式,深受 web 开发、可视化从业者的喜爱。所以,其对应的工具链也比较丰富。

在网站上用 polyline 画好地图后,下载成 geojson 格式。

转化为 gpx 的方式也很简单,模仿前面的文件格式,写一个模板,然后用 jinja2 给填上去就行。

GPX 文件模板

除了填模板外,这里有一些细节需要注意:

Geojson 里面是没有时间的,但运动记录一定有时间。如果没有时间,会被报告格式非法。

Strava 接受的时间格式是 “%Y-%m-%dT%H:%M:%S+08:00” ,其他字符串格式的时间表达,可能不会通过。

第一个记录点的时间,需要比运动开始的时间晚一点(不知道为什么),否则可能报错。

Strava 使用运动开始的时间来去重。所以如果多次创造轨迹的话,需要采用不同的时间。

当然,这些细节已经包括在我写的脚本里了,已经开源,大家可以直接用: https://github.com/hupili/geojson-to-gpx-with-time[2]

寄语

从此以后,妈妈再也不用担心你的表没电了。

REF

[1] https://geojson.io/: https://geojson.io/

[2] https://github.com/hupili/geojson-to-gpx-with-time: https://github.com/hupili/geojson-to-gpx-with-time

[3] Have fun with GPX File : https://docs.google.com/presentation/d/1bYXCX1LiHKYHE7ADZyFckhjJFrieoH3horXawBaigVs/edit#slide=id.p

博闻 | 明察 | 躬行
心法 | 手艺 | 随想