Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Paul M.Ответов: 4

Я новый пользователь 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>
  • Из любопытства: Вы когда-нибудь догадывались об этом? simbabque 21.11.2012

pythonextractgpxperl

Ответы

Ответ 1 · рейтинг 12 · Charles P.

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

С Уважением

Ответ 2 · рейтинг 9 · Martijn Pieters

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

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

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

Ответ 3 · рейтинг 8 · simbabque

Поскольку Мартейн опубликовал ответ на 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 - сокращение от слов в кавычках и он делает именно это: возвращает список строк в нем, но в кавычках. Мы могли бы также сказать ('time', 'lat', 'long'... ).

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

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

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

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

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

Ответ 4 · рейтинг 1 · user2589273

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы