[英]How to extract .gpx data with python
我是一个新的 linux/python 用户,拥有.gpx 文件(由 GPS 跟踪软件制作的输出文件),需要将值提取到 csv/txt 中以用于 GIS 程序。 我在开始的 python 书、本网站和在线中查找了字符串和切片等。 我使用了 a.gpx to.txt 转换器,可以将经度和纬度提取到文本文件中。 我需要提取高程数据。 该文件顶部有六行文本,我只知道如何在 emacs 中打开此文件(除了在网站上上传) 这是从第 7 行开始的文件。
理想情况下,我想知道如何通过 python(或 Perl)将所有值提取到 csv 或 txt 文件中。 如果有人知道网站教程或示例脚本,将不胜感激。
<metadata>
<time>2012-06-13T01:51:08Z</time>
</metadata>
<trk>
<name>Track 2012-06-12 19:51</name>
<trkseg>
<trkpt lat="43.49670697" lon="-112.03380961">
<ele>1403.0</ele>
<time>2012-06-13T01:53:44Z</time>
<extensions>
<ogt10:accuracy>34.0</ogt10:accuracy></extensions>
</trkpt>
<trkpt lat="43.49796612" lon="-112.03970968">
<ele>1410.9000244140625</ele>
<time>2012-06-13T01:57:10Z</time>
<extensions>
<gpx10:speed>3.75</gpx10:speed>
<ogt10:accuracy>13.0</ogt10:accuracy>
<gpx10:course>293.20001220703125</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49450857" lon="-112.04477274">
<ele>1406.5</ele>
<time>2012-06-13T02:02:24Z</time>
<extensions>
<ogt10:accuracy>12.0</ogt10:accuracy></extensions>
</trkpt>
</trkseg>
<trkseg>
<trkpt lat="43.49451057" lon="-112.04480354">
<ele>1398.9000244140625</ele>
<time>2012-06-13T02:54:55Z</time>
<extensions>
<ogt10:accuracy>10.0</ogt10:accuracy></extensions>
</trkpt>
<trkpt lat="43.49464813" lon="-112.04472215">
<ele>1414.9000244140625</ele>
<time>2012-06-13T02:56:06Z</time>
<extensions>
<ogt10:accuracy>7.0</ogt10:accuracy></extensions>
</trkpt>
<trkpt lat="43.49432573" lon="-112.04489684">
<ele>1410.9000244140625</ele>
<time>2012-06-13T02:57:27Z</time>
<extensions>
<gpx10:speed>3.288236618041992</gpx10:speed>
<ogt10:accuracy>21.0</ogt10:accuracy>
<gpx10:course>196.1999969482422</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49397445" lon="-112.04505216">
<ele>1421.699951171875</ele>
<time>2012-06-13T02:57:30Z</time>
<extensions>
<gpx10:speed>3.0</gpx10:speed>
<ogt10:accuracy>17.0</ogt10:accuracy>
<gpx10:course>192.89999389648438</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49428702" lon="-112.04265923">
<ele>1433.0</ele>
<time>2012-06-13T02:58:46Z</time>
<extensions>
<gpx10:speed>4.5</gpx10:speed>
<ogt10:accuracy>18.0</ogt10:accuracy>
<gpx10:course>32.400001525878906</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49444603" lon="-112.04263691">
<ele>1430.199951171875</ele>
<time>2012-06-13T02:58:50Z</time>
<extensions>
<gpx10:speed>4.5</gpx10:speed>
<ogt10:accuracy>11.0</ogt10:accuracy>
<gpx10:course>29.299999237060547</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49456961" lon="-112.04260058">
<ele>1430.4000244140625</ele>
<time>2012-06-13T02:58:52Z</time>
<extensions>
<gpx10:speed>4.5</gpx10:speed>
<ogt10:accuracy>8.0</ogt10:accuracy>
<gpx10:course>28.600000381469727</gpx10:course></extensions>
</trkpt>
<trkpt lat="43.49570131" lon="-112.04001132">
<ele>1418.199951171875</ele>
<time>2012-06-13T03:00:08Z</time>
<extensions>
你可以安装GPXpy
sudo pip install gpxpy
然后只需使用库:
import gpxpy
import gpxpy.gpx
gpx_file = open('input_file.gpx', 'r')
gpx = gpxpy.parse(gpx_file) \
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
print 'Point at ({0},{1}) -> {2}'.format(point.latitude, point.longitude, point.elevation)
for waypoint in gpx.waypoints:
print 'waypoint {0} -> ({1},{2})'.format(waypoint.name, waypoint.latitude, waypoint.longitude)
for route in gpx.routes:
print 'Route:'
更多信息: https : //pypi.python.org/pypi/gpxpy
问候
GPX 是一种 XML 格式,因此使用lxml之类的拟合模块或包含的ElementTree XML API来解析数据,然后使用 python csv
模块输出到 CSV。
涵盖这些概念的教程:
我还发现了一个名为gpxpy的 python GPX 解析库,它可能为 GPX 文件中包含的数据提供了一个更高级别的接口。
由于 Martijn 发布了一个 Python 答案并说 Perl 会变成行噪声,我觉得也需要一个 Perl 答案。
在 Perl 模块目录CPAN 上,有一个名为Geo::Gpx的模块。 正如 Martijn 已经说过的,GPX 是一种 XML 格式。 但幸运的是,已经有人把它做成了一个模块,为我们处理解析。 我们所要做的就是加载该模块。
有多个模块可用于 CSV 处理,但此 XML 文件中的数据相当简单,因此我们实际上并不需要一个。 我们可以使用内置功能自行完成。
请考虑以下脚本。 我会在一分钟内给出解释。
use strict;
use warnings;
use Geo::Gpx;
use DateTime;
# Open the GPX file
open my $fh_in, '<', 'fells_loop.gpx';
# Parse GPX
my $gpx = Geo::Gpx->new( input => $fh_in );
# Close the GPX file
close $fh_in;
# Open an output file
open my $fh_out, '>', 'fells_loop.csv';
# Print the header line to the file
print $fh_out "time,lat,lon,ele,name,sym,type,desc\n";
# The waypoints-method of the GEO::GPX-Object returns an array-ref
# which we can iterate in a foreach loop
foreach my $wp ( @{ $gpx->waypoints() } ) {
# Some fields seem to be optional so they are missing in the hash.
# We have to add an empty string by iterating over all the possible
# hash keys to put '' in them.
$wp->{$_} ||= '' for qw( time lat lon ele name sym type desc );
# The time is a unix timestamp, which is hard to read.
# We can make it an ISO8601 date with the DateTime module.
# We only do it if there already is a time, though.
if ($wp->{'time'}) {
$wp->{'time'} = DateTime->from_epoch( epoch => $wp->{'time'} )
->iso8601();
}
# Join the fields with a comma and print them to the output file
print $fh_out join(',', (
$wp->{'time'},
$wp->{'lat'},
$wp->{'lon'},
$wp->{'ele'},
$wp->{'name'},
$wp->{'sym'},
$wp->{'type'},
$wp->{'desc'},
)), "\n"; # Add a newline at the end
}
# Close the output file
close $fh_out;
让我们分步骤进行:
use strict
和use warnings
强制执行诸如声明变量之类的规则,并告诉您最难发现的常见错误。use Geo::Gpx
和use DateTime
是我们使用的模块。 Geo::Gpx
将为我们处理解析。 我们需要DateTime
将 unix 时间戳转换为可读的日期和时间。open
函数打开一个文件。 $fh_in
是保存文件句柄的变量。 我们要阅读的 GPX 文件是falls_loop.gpx ,我冒昧地从topografix.com借用了它。 您可以在perlpentut 中找到有关open
更多信息。$gpx
的新Geo::Gpx
对象,并使用我们的文件句柄$fh_in
告诉它从哪里读取 XML 数据。 new
-method 由所有具有面向对象接口的 Perl 模块提供。close
关闭文件句柄。open
有一个>
来告诉 Perl 我们要写入这个文件句柄。print
到文件句柄。 请注意,文件句柄后没有逗号。 \\n
是换行符。 foreach
循环采用Geo::Gpx
对象的waypoints
方法的返回值。 该值是一个数组引用。 把它想象成一个包含数组的数组(如果你想了解更多关于引用的信息,请参阅perlref )。 在循环的每次迭代中,该数组 ref 的下一个元素(代表 GPX 数据中的一个航点)将被放入$wp
。 如果用Data::Dumper
打印,它看起来像这样:
$VAR1 = { 'ele' => '64.008000', 'lat' => '42.455956', 'time' => 991452424, 'name' => 'SOAPBOX', 'sym' => 'Cemetery', 'desc' => 'Soap Box Derby Track', 'lon' => '-71.107483', 'type' => 'Intersection' };
现在后缀for
有点棘手。 正如我们刚刚看到的,hashref 中有 8 个键。 不幸的是,其中一些有时会丢失。 因为我们use warnings
,所以如果我们尝试访问这些缺失值之一,我们将收到警告。 我们必须创建这些键并在其中放置一个空字符串''
。
foreach
和for
在 Perl 中是完全可以互换的,并且两者也可以在单个表达式后面的后缀语法中使用。 我们用qw
-运算符来创建列表是for
将迭代。 qw
是带引号的单词的缩写,它就是这样做的:它返回其中的字符串列表,但被引用。 我们也可以说('time', 'lat', 'long'... )
。
在表达式中,我们访问$wp
每个键。 $_
是循环变量。 在第一次迭代中,它将保存“时间”,然后是“纬度”,依此类推。 由于$wp
是一个 hashref,我们需要->
来访问它的键。 花括号表明它是一个 hashref。 ||=
运算符仅在它不是真值时才为我们的哈希 ref 元素分配一个值。
现在,如果有时间值(如果未设置日期,我们刚刚分配的空字符串被视为“没有”),我们将用正确的日期替换 unix 时间戳。 DateTime帮助我们做到这一点。 from_epoch
方法获取 unix 时间戳作为参数。 它返回一个DateTime
对象,我们可以直接使用它来调用它的iso8601
函数。
这称为链接。 有些模块可以做到。 它类似于 jQuery 的 JavaScript 对象所做的。 我们 hashref 中的 unix 时间戳被DateTime
操作的结果替换。
print
到我们的文件句柄。 join
用于在值之间放置逗号。 我们还在最后放了一个换行符。close
文件句柄。总而言之,我会说这很简单,也很可读,不是吗? 我试图将过于冗长的语法与 _Perl_ish 风格完美结合。
每次我尝试这样做时,我都会在互联网上搜索解决方案并最终编写自己的正则表达式解析器。
import re
import numpy as np
GPXfile='Lunch_Walk.gpx'
data = open(GPXfile).read()
lat = np.array(re.findall(r'lat="([^"]+)',data),dtype=float)
lon = np.array(re.findall(r'lon="([^"]+)',data),dtype=float)
time = re.findall(r'<time>([^\<]+)',data)
combined = np.array(list(zip(lat,lon,time)))
这给出了一个格式数组:
array([['51.504613', '-0.141894', '2020-12-26T12:43:14Z'],
['51.504624', '-0.141901', '2020-12-26T13:10:26Z'],
['51.504633', '-0.141906', '2020-12-26T13:10:28Z'],
...)
然后,您可以随心所欲地使用它。
虽然gpxpy
是流行的 python 答案,我自己找到了这个答案并尝试了它,但我发现它很难获得像心率这样的扩展类型数据,即使不是不可能,也很难,而且仍然必须遍历各种嵌套的 xml 祖先/孩子们所以我写了gpxcsv 。
一样容易:
from gpxcsv import gpxtolist
import pandas as pd
df = pd.DataFrame(
pxtolist('myfile.gpx'))
对于数据框,或者存在一个命令行工具来创建一个 csv 或 json 文件,在跟踪点中保留尽可能多的列,因为它使用标签作为列名。
该项目的源代码在 github 上。
Geopandas 还能够将.gpx 文件打开为 dataframe 再次依赖 GDAL(查看他们支持的矢量格式)。 由于 .gpx 是 XML 格式,因此 .gpx 也比常规的 dataframe 更嵌套。 这就是您必须定义要打开的层的原因。
要将元数据保存在单行的 dataframe 中(您可能已经将整个轨道存储为线串,因此没有时间戳):
import geopandas as gpd
df = gpd.read_file("myfile.gpx", layer='tracks')
要获得每个跟踪点等于一行的实际轨迹,请执行以下操作:
df = gpd.read_file("myfile.gpx", layer='track_points')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.