2012-06-19 68 views
6

Soy un nuevo usuario de linux/python y tengo archivos .gpx (archivos de salida que están hechos de software de seguimiento GPS) y necesito extraer valores en csv/txt para utilizarlos en un programa GIS . He buscado cadenas y troceado, etc. en mi libro de Python, en este sitio web y en línea. He usado un convertidor de .gpx a .txt y puedo extraer la longitud y la latitud en un archivo de texto. Necesito extraer los datos de elevación. El archivo tiene seis líneas de texto en la parte superior y solo sé cómo abrir este archivo en emacs (además de cargarlo en un sitio web) Aquí está el archivo que comienza en la línea 7.Cómo extraer datos .gpx con python

De manera óptima, me gustaría saber cómo para extraer todos los valores a través de python (o Perl) en un archivo csv o txt. Si alguien conoce un tutorial de sitio web o un script de muestra, se lo agradecería.

<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> 
+0

Por curiosidad: ¿Alguna vez ha dado cuenta de esto ¿fuera? – simbabque

Respuesta

7

GPX is an XML format, a fin de utilizar un módulo apropiado como lxml o el incluido ElementTree XML API para analizar los datos, entonces la salida a CSV usando el pitón csv module.

tutoriales que cubren estos conceptos:

También encontraron una biblioteca de análisis pitón GPX llama gpxpy que tal vez da una de mayor nivel interfaz a los datos contenidos en los archivos GPX.

+0

Voy a intentar esto. Alguien también me sugirió que Perl podría ser una forma de extraer esto. Como soy igualmente novato de ambos, primero veré tus tutoriales mencionados. ¡Gracias, Martijn! –

+0

Perl sería igualmente adecuado para la tarea; hay analizadores XML Perl y bibliotecas CSV, al igual que para Python. Sin embargo, es posible que Python sea más fácil de aprender; en mi opinión personal, Perl se convierte demasiado fácilmente en ruido de línea. –

+0

¡Tomaré su palabra, gracias! –

6

Dado que Martijn publicó una respuesta de Python y dijo que Perl recurriría al ruido de la línea, sentí que también necesitaba una respuesta Perl.

En CPAN, el directorio del módulo Perl, hay un módulo llamado Geo::Gpx. Como ya dijo Martijn, GPX es un formato XML. Pero, afortunadamente, alguien ya lo ha convertido en un módulo que maneja el análisis sintáctico para nosotros. Todo lo que tenemos que hacer es cargar ese módulo.

Existen varios módulos disponibles para el manejo de CSV, pero los datos en este archivo XML son bastante simples, por lo que realmente no los necesitamos. Podemos hacerlo por nuestra cuenta con la funcionalidad incorporada.

Tenga en cuenta la siguiente secuencia de comandos. Daré una explicación en un minuto.

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; 

Tomemos esto en pasos:

  • use strict y use warnings hacer cumplir las reglas, como la declaración de variables y le informará sobre los errores comunes que son los más difíciles de encontrar.
  • use Geo::Gpx y use DateTime son los módulos que usamos. Geo::Gpx va a manejar el análisis sintáctico para nosotros. Necesitamos DateTime para hacer que las marcas de fecha y hora de Unix sean fechas y horas legibles.
  • La función open abre un archivo. $fh_in es la variable que contiene el identificador de archivo. El archivo GPX que queremos leer es fells_loop.gpx que me tomé la libertad de tomar prestada de topografix.com. Puede encontrar más información en open en perlopentut.
  • Creamos un nuevo objeto Geo::Gpx llamado $gpx y usamos nuestro identificador de archivos $fh_in para indicarle dónde leer los datos XML. El método new es proporcionado por todos los módulos Perl que tienen una interfaz orientada a objetos.
  • close cierra el identificador de archivo.
  • El siguiente open tiene un para decirle a Perl que queremos escribir en este identificador de archivo.
  • Nos print a un manejador de archivos poniéndolo como el primer argumento para print. Tenga en cuenta que no hay coma después de Filehandle. El \n es un carácter de nueva línea.
  • El foreach loop toma el valor de retorno del waypoints -metodo del objeto Geo::Gpx. Este valor es una referencia de matriz. Piense en esto como una matriz que contiene matrices (consulte perlref si desea obtener más información acerca de las referencias). En cada iteración del ciclo, el siguiente elemento de esa matriz ref (que representa un waypoint en los datos GPX) se pondrá en $wp. Si impreso con Data::Dumper se ve así:

    $VAR1 = { 
         'ele' => '64.008000', 
         'lat' => '42.455956', 
         'time' => 991452424, 
         'name' => 'SOAPBOX', 
         'sym' => 'Cemetery', 
         'desc' => 'Soap Box Derby Track', 
         'lon' => '-71.107483', 
         'type' => 'Intersection' 
        }; 
    
  • Ahora el postfixfor es un poco complicado. Como acabamos de ver, hay 8 claves en el hashref. Desafortunadamente, algunos de ellos a veces se pierden. Como tenemos use warnings, recibiremos una advertencia si intentamos acceder a uno de estos valores faltantes. Tenemos que crear estas claves y poner una cadena vacía '' allí.

    foreach y for son completamente intercambiables en Perl, y ambos también pueden usarse en sintaxis postfix detrás de una sola expresión. Usamos el operador qw para crear la lista que se iterará en for. qw es la abreviatura de con las palabras entrecomilladas y hace precisamente eso: devuelve una lista de las cadenas en ella, pero citadas. También podríamos haber dicho ('time', 'lat', 'long'...).

    En la expresión, accedemos a cada clave de $wp. $_ es la variable de bucle. En la primera iteración contendrá 'tiempo', luego 'lat' y así sucesivamente. Como $wp es un hashref, necesitamos el -> para acceder a sus claves. Las llaves dicen que es un hashref. El ||= operator asigna un valor a nuestro elemento hash ref solo si no es un valor verdadero.

  • Ahora, si hay un valor de tiempo (la cadena vacía que acabamos de asignar si la fecha no se estableció se considera como 'no hay ninguno'), reemplazamos la marca de tiempo de unix con una fecha apropiada. DateTime nos ayuda a hacer eso. El método from_epoch obtiene la marca de tiempo de unix como argumento. Devuelve un objeto DateTime que podemos usar directamente para llamar a la función iso8601.

    Esto se llama encadenamiento. Algunos módulos pueden hacerlo. Es similar a lo que hacen los objetos JavaScript de jQuery. La marca de tiempo de unix en nuestro hashref se reemplaza con el resultado de la operación DateTime.

  • Ahora print en nuestra manejador de archivos de nuevo. join se usa para poner comas entre los valores. También colocamos una nueva línea al final otra vez.
  • Una vez que hayamos terminado con el ciclo, tendremos close el identificador de archivo.
  • ¡Ya hemos terminado! :)

Con todo, yo diría que esto es bastante simple y también bastante legible, ¿no? Traté de hacer una mezcla sana de sintaxis demasiado prolija con un sabor _Perl_ish.

+0

¡Gracias por tu guión! Fui a CPAN, busqué @ readme y tuve errores. el comando perl Makefile.PL resultó en: ExtUtils :: MakeMaker :: Coverage opcional no disponible El argumento "6.57_05" no es numérico en ge numérico (> =) en Makefile.PL línea 34. Verifica si tu kit está completo. .. Se ve bien Advertencia: prerrequisito DateTime :: Format :: ISO8601 0 no encontrado. Advertencia: requisito previo HTML :: Entidades 0 no encontrado. Advertencia: requisito previo XML :: Descent 1.01 no encontrado. Escribiendo Makefile para Geo :: Gpx Escribiendo MYMETA.yml procedido con make test & 8/10 tests & 3/3 subtests failed. intenté solo ejecutar lat, lon, elev, w/noluck –

+0

, así que tengo 4 páginas de errores de la prueba de prueba, aunque intenté eliminar el tiempo y todos los demás campos del texto, aparte de lat, lon, elev y ejecutarlo de todos modos, sin suerte Leí mis primeros 3 capítulos del libro perl de principio ayer, así que espero que haya una solución fácil, también intenté reinstalarlo bajo sudo sin suerte. el guion tiene sentido y aprecio la porción de explicación también. Siendo un novato, me estoy rascando la cabeza en este momento. –

+0

¿Has leído un manual sobre cómo [instalar los módulos de cpan] (http://www.cpan.org/modules/INSTALL.html)? ¿O intentó descargarlo desde el sitio web de CPAN? Si usa la herramienta de línea de comandos, instalará todas las dependencias. – simbabque

3

Puede instalar GPXpy

sudo pip install gpxpy 

Entonces sólo tiene que utilizar la biblioteca:

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:' 

Para más información: https://pypi.python.org/pypi/gpxpy

Saludos

Cuestiones relacionadas