Как извлечь данные .gpx с помощью python

Я новый пользователь linux/python и имею файлы .gpx (выходные файлы, созданные с помощью программного обеспечения для отслеживания GPS), и мне нужно извлечь значения в csv/txt для использования в программе ГИС. Я просмотрел строки, нарезку и т. д. в моей начальной книге по Python, на этом веб-сайте и в Интернете. Я использовал конвертер .gpx в .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>

person Paul M.    schedule 19.06.2012    source источник
comment
Из любопытства: Вы когда-нибудь догадывались об этом?   -  person simbabque    schedule 21.11.2012


Ответы (4)


Вы можете установить 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.

С Уважением

person Charles P.    schedule 18.06.2016

GPX — это формат XML, поэтому используйте подходящий модуль, например lxml или включенный ElementTree XML API для анализа данных и последующего вывода в CSV с помощью csv модуля python.

Учебники, охватывающие эти понятия:

Я также нашел библиотеку синтаксического анализа GPX для Python под названием gpxpy, которая, возможно, предоставляет интерфейс более высокого уровня для данных, содержащихся в GPX-файлы.

person Martijn Pieters    schedule 19.06.2012
comment
Я попробую. Кто-то также подсказал мне, что Perl может быть способом их извлечения. Поскольку я в равной степени новичок в обоих, я сначала рассмотрю упомянутые вами учебники. Спасибо Мартейн! - person Paul M.; 19.06.2012
comment
Perl в равной степени подходит для этой задачи; есть XML-парсеры Perl и библиотеки CSV, как и для python. Однако вам может показаться, что Python легче изучать; по моему личному мнению, Perl слишком легко превращается в линейный шум. - person Martijn Pieters; 19.06.2012

Поскольку Мартейн опубликовал ответ на Python и сказал, что Perl превратится в линейный шум, я почувствовал, что есть потребность в ответе на Perl.

В CPAN, каталоге модулей Perl, есть модуль с именем Geo::Gpx. Как уже сказал Мартин, 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, который мы хотим прочитать, называется fells_loop.gpx, который я взял на себя смелость позаимствовать у topografix.com. Дополнительную информацию о open можно найти в perlopentut.
  • Мы создаем новый объект Geo::Gpx с именем $gpx и используем наш дескриптор файла $fh_in, чтобы сообщить ему, откуда считывать XML-данные. Метод new предоставляется всеми модулями Perl, имеющими объектно-ориентированный интерфейс.
  • close закрывает дескриптор файла.
  • Следующий open имеет >, чтобы сообщить Perl, что мы хотим записать в этот дескриптор файла.
  • Мы print получаем дескриптор файла, помещая его в качестве первого аргумента в print. Обратите внимание, что после дескриптора файла запятая не ставится. \n — это символ новой строки.
  • foreach цикл принимает возвращаемое значение waypoints-метода объекта Geo::Gpx . Это значение является ссылкой на массив. Думайте об этом как о массиве, который содержит массивы (см. 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, и оба могут также использоваться в синтаксисе postfix за одним выражением. Мы используем qw-оператор для создания списка, который for будет перебирать. qw — сокращение от слов в кавычках< /strong> и он делает именно это: возвращает список строк в нем, но в кавычках. Мы могли бы также сказать ('time', 'lat', 'long'... ).

    В выражении мы получаем доступ к каждому ключу $wp. $_ — это переменная цикла. В первой итерации он будет содержать «время», затем «лат» и так далее. Поскольку $wp — это хэш-ссылка, нам нужен -> для доступа к его ключам. Фигурные скобки говорят, что это hashref. ||= оператор присваивает значение только нашему элементу хэша ref если это не истинное значение.

  • Теперь, если есть значение времени (пустая строка, которую мы только что присвоили, если дата не была установлена, рассматривается как «ничего нет»), мы заменяем метку времени unix на правильную дату. В этом нам помогает DateTime. Метод from_epoch получает временную метку unix в качестве аргумента. Он возвращает объект DateTime, который мы можем напрямую использовать для вызова на нем функции iso8601.

    Это называется цепочкой. Некоторые модули могут это сделать. Это похоже на то, что делают объекты JavaScript jQuery. Временная метка unix в нашем hashref заменяется результатом операции DateTime.

  • Теперь мы снова print к нашему файловому дескриптору. join используется для помещения запятых между значениями. Мы также ставим новую строку в конце снова.
  • Как только мы закончим с циклом, мы close дескриптор файла.
  • Теперь мы закончили! :)

В целом, я бы сказал, что это довольно просто, а также довольно читабельно, не так ли? Я попытался сделать его здоровой смесью чрезмерно многословного синтаксиса с привкусом _Perl_ish.

person simbabque    schedule 19.06.2012
comment
Спасибо за ваш сценарий! Я пошел в CPAN, посмотрел @ readme и обнаружил ошибки. команда perl Makefile.PL привела к следующему результату: Необязательный ExtUtils::MakeMaker::Coverage недоступен. Аргумент 6.57_05 не является числовым в числовом формате ge (›=) в строке 34 Makefile.PL. Проверка комплектности комплекта... Выглядит хорошее Предупреждение: предварительное условие DateTime::Format::ISO8601 0 не найдено. Предупреждение: предварительное условие HTML::Entities 0 не найдено. Предупреждение: предварительная версия XML::Descent 1.01 не найдена. Написание Makefile для Geo::Gpx Написание MYMETA.yml продолжалось с тестом make, 8/10 тестов и 3/3 подтестов не прошли. пытался бегать только по широте, долготе, высоте, без лука - person Paul M.; 22.06.2012
comment
поэтому у меня есть 4 страницы ошибок из теста make, хотя я пытался удалить время и все другие поля из текста, кроме lat, lon, elev, и все равно запустить его, но безуспешно. Вчера я прочитал свои первые 3 главы начальной книги Perl, поэтому я надеюсь, что это легко исправить, я также безуспешно пытался переустановить под sudo. сценарий имеет смысл, и я также ценю пояснительную часть. Я как новичок пока ломаю голову. - person Paul M.; 22.06.2012
comment
Вы читали руководство по установке модулей cpan? Или вы пытались скачать его с сайта CPAN? Если вы используете инструмент командной строки, он установит все зависимости. - person simbabque; 22.06.2012
comment
А, в разделе Beginning Perl должно быть рассказано все о cpan в главе 2. Если вы используете Windows с ActivePerl, есть также программа под названием ppm, которая предоставит вам приятный графический интерфейс для установки модулей. Вы можете использовать любой из них, чтобы получить нужные вам модули со всеми зависимостями за один раз. - person simbabque; 22.06.2012
comment
Звучит здорово, я посмотрю на это, вы правы, я получил загрузку с сайта, хотя я посмотрю, как загрузить в командной строке в bash/ubuntu. - person Paul M.; 22.06.2012
comment
Опять же, не просто загружайте, но и устанавливайте с помощью cpan. Это самый простой способ. Вы можете загрузить его и установить с помощью make-файла, но зачем беспокоиться, если cpan и i MODULE::NAME могут позаботиться об этом за вас? ;) - person simbabque; 22.06.2012
comment
Привет Simbabque, почти там, хотя и не совсем. Я установил модули для DateTime::Format::ISO8601 и XML::Descent, которые переместили меня на Line19 вашего скрипта. Он создал заголовки в .csv, которые я считаю прогрессом. Я просто читаю о массивах в книге Beg.Perl, а также получаю эту ошибку: Невозможно использовать неопределенное значение в качестве ссылки на МАССИВ в строке 19 gpxscript. Не то чтобы я много знал о массивах... в книге говорится, что массив должен начинаться с альфа-символа или символа подчеркивания. это все, что я могу придумать... Я назвал массив @array, и это тоже не помогло. Я застрял... - person Paul M.; 28.06.2012
comment
@ПолМ. Единственный тонкий элемент в строке 19, который является ссылкой ARRAY (см. Intermediate Perl, глава 4), — это @{ $gpx->waypoints() }. Вызывается метод waypoints() объекта $gpx (назовем его так для простоты). Возвращает ссылку на массив. @{ } превращает эту ссылку в фактический массив (называемый разыменованием). Но в этом случае он возвращает не ссылку на массив, а undef. Таким образом, кажется, нет никаких данных, которые он может вернуть. Вы установили модуль, потому что он не стонет по этому поводу. Файл, который вы читаете, там? Проверьте оператор open. - person simbabque; 28.06.2012

Каждый раз, когда я пытаюсь это сделать, я роюсь в Интернете в поисках решений и заканчиваю тем, что пишу свой собственный парсер регулярных выражений.

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'],
       ...)

Затем вы можете делать с этим все, что пожелаете.

person user2589273    schedule 26.12.2020