2012-06-19 33 views
6

Sono un nuovo utente linux/python e ho file .gpx (file di output creati dal software di localizzazione GPS) e ho bisogno di estrarre i valori in csv/txt per l'uso in un programma GIS . Ho cercato le stringhe e le affettature ecc. Nel mio libro Python iniziale, questo sito web e online. Ho usato un convertitore .gpx in .txt e posso estrarre la longitudine e la latitudine in un file di testo. Ho bisogno di estrarre i dati di elevazione. Il file ha sei righe di testo nella parte superiore e so solo come aprire questo file in emacs (oltre al caricamento su un sito Web) Ecco il file che inizia alla riga 7.Come estrarre i dati .gpx con python

In modo ottimale, mi piacerebbe sapere come per estrarre tutti i valori tramite python (o Perl) in un file csv o txt. Se qualcuno conosce un tutorial sul sito Web o uno script di esempio, sarebbe apprezzato.

<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

curiosità: avete mai pensato questo su? – simbabque

risposta

7

GPX is an XML format, quindi utilizzare un modulo raccordo come lxml o incluso ElementTree XML API per analizzare i dati, poi output CSV utilizzando il pitone csv module.

Tutorial che coprono questi concetti:

ho anche trovato una libreria di analisi pitone GPX chiamato gpxpy che forse dà un superiore che livello interfaccia ai dati contenuti nei file GPX.

+0

Farò un tentativo. Qualcuno mi ha anche suggerito che Perl potrebbe essere un modo per estrarli. Dato che sono ugualmente un novizio per entrambi, guarderò prima i tuoi tutorial menzionati. Grazie Martijn! –

+0

Perl sarebbe ugualmente adatto per l'attività; ci sono parser XML Perl e librerie CSV, proprio come per Python. Tuttavia, potresti trovare Python più facile da imparare; secondo la mia opinione personale, Perl si dedica troppo facilmente al rumore di linea. –

+0

Ti crederò sulla parola, grazie! –

6

Poiché Martijn ha pubblicato una risposta in Python e ha detto che Perl si sarebbe trasformata in rumore di linea, ho sentito che c'era anche bisogno di una risposta Perl.

Su CPAN, la directory del modulo Perl, esiste un modulo chiamato Geo::Gpx. Come già detto Martijn, GPX è un formato XML. Ma per fortuna qualcuno lo ha già trasformato in un modulo che gestisce l'analisi per noi. Tutto quello che dobbiamo fare è caricare quel modulo.

Ci sono diversi moduli disponibili per la gestione CSV, ma i dati in questo file XML sono piuttosto semplici, quindi non ne abbiamo davvero bisogno. Possiamo farlo da soli con la funzionalità integrata.

Si prega di considerare il seguente script. Darò una spiegazione tra 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; 

Prendiamo questo in passi:

  • use strict e use warnings far rispettare le regole come le variabili che dichiarano e raccontare gli errori più comuni che sono i più difficili da trovare.
  • use Geo::Gpx e use DateTime sono i moduli che utilizziamo. Geo::Gpx gestirà l'analisi per noi. Abbiamo bisogno di DateTime per rendere i timestamp unix in date e orari leggibili.
  • La funzione open apre un file. $fh_in è la variabile che contiene il filehandle. Il file GPX che vogliamo leggere è fells_loop.gpx che ho preso la libertà di prendere in prestito da topografix.com. Puoi trovare maggiori informazioni su open in perlopentut.
  • Creiamo un nuovo oggetto Geo::Gpx chiamato $gpx e utilizziamo il nostro filehandle $fh_in per indicare da dove leggere i dati XML. Il metodo new è fornito da tutti i moduli Perl dotati di un'interfaccia orientata agli oggetti.
  • close chiude il filehandle.
  • Il prossimo open ha un > per dire a Perl che vogliamo scrivere su questo filehandle.
  • Noi print in un filehandle ponendolo come primo argomento su print. Si noti che non esiste una virgola dopo il filehandle. Il \n è un carattere di nuova riga.
  • Il numero foreach loop assume il valore restituito del metodo waypoints dell'oggetto Geo::Gpx. Questo valore è un riferimento di matrice. Pensa a questo come a un array che contiene array (vedi perlref se vuoi saperne di più sui riferimenti). In ogni iterazione del ciclo, l'elemento successivo di tale riferimento dell'array (che rappresenta un waypoint nei dati GPX) verrà inserito in $wp. Se stampate con Data::Dumper sembra che questo:

    $VAR1 = { 
         'ele' => '64.008000', 
         'lat' => '42.455956', 
         'time' => 991452424, 
         'name' => 'SOAPBOX', 
         'sym' => 'Cemetery', 
         'desc' => 'Soap Box Derby Track', 
         'lon' => '-71.107483', 
         'type' => 'Intersection' 
        }; 
    
  • Ora il postfixfor è un po 'complicato. Come abbiamo appena visto, ci sono 8 chiavi nell'hashref. Sfortunatamente, a volte mancano alcuni di loro. Poiché abbiamo use warnings, riceveremo un avviso se proviamo ad accedere a uno di questi valori mancanti. Dobbiamo creare queste chiavi e inserire una stringa vuota '' qui.

    foreach e for sono completamente intercambiabili in Perl, ed entrambi possono essere utilizzati anche in suffisso sintassi dietro una singola espressione. Usiamo il qw -operator per creare l'elenco che for itererà. qw è l'abbreviazione di parole quotate e fa proprio questo: restituisce un elenco delle stringhe in esso contenute, ma citato. Potremmo anche dire ('time', 'lat', 'long'...).

    Nell'espressione, si accede a ciascun tasto di $wp. $_ è la variabile di ciclo. Nella prima iterazione manterrà 'time', then 'lat' e così via. Poiché $wp è un hashref, abbiamo bisogno del -> per accedere alle sue chiavi. Le parentesi graffe dicono che è un hashref. Lo ||= operator assegna un valore al nostro elemento ref hash solo se non è un valore vero.

  • Ora, se c'è un valore di tempo (la stringa vuota che abbiamo appena assegnato se la data non è stata impostata è considerata "non ce n'è"), sostituiamo la data e l'ora di unix con una data appropriata. DateTime ci aiuta a farlo. Il metodo from_epoch ottiene come argomento un timestamp unix. Restituisce un oggetto DateTime che possiamo utilizzare direttamente per chiamare la funzione iso8601 su di esso.

    Questo è chiamato concatenamento. Alcuni moduli possono farlo. È simile a ciò che fanno gli oggetti JavaScript di jQuery. Il timestamp unix nel nostro hashref viene sostituito con il risultato dell'operazione DateTime.

  • Ora abbiamo di nuovo il file print. join viene utilizzato per inserire virgole tra i valori. Abbiamo anche rimesso una newline alla fine.
  • Una volta terminato il ciclo, abbiamo close il filehandle.
  • Ora abbiamo finito! :)

Tutto sommato, direi che questo è piuttosto semplice e anche abbastanza leggibile, non è vero? Ho cercato di renderlo un mix salutare di sintassi eccessivamente prolissa con un sapore _Perl_ish.

+0

Grazie per il tuo copione! Sono andato a CPAN, guardato @ readme e avendo errori. il comando perl Makefile.PL ha prodotto: ExtUtils facoltativo :: MakeMaker :: Copertura non disponibile L'argomento "6.57_05" non è numerico in numeric ge (> =) alla riga Makefile.PL 34. Verifica se il kit è completo. .. Sembra buono Attenzione: prerequisito DateTime :: Format :: ISO8601 0 non trovato. Avviso: prerequisito HTML :: Entità 0 non trovata. Attenzione: prerequisito XML :: Descent 1.01 non trovato. Scrittura Makefile per Geo :: Gpx Scrittura MYMETA.yml proceduto w/make test e 8/10 test e 3/3 sottotest non riuscito. ho provato a eseguire solo lat, lon, elev, w/noluck –

+0

quindi ho 4 pagine di errori dal make test, anche se ho tentato di rimuovere il tempo e tutti gli altri campi dal testo oltre a lat, lon, elev e lo eseguo comunque, senza fortuna. Ho letto i miei primi 3 capitoli all'inizio del libro perl ieri, quindi spero che sia facile e veloce, ho anche provato a reinstallare sudo senza fortuna. la sceneggiatura ha un senso e apprezzo anche la parte della spiegazione. Essendo un novizio sto grattando la testa in questo momento. –

+0

Hai letto un manuale su come installare [moduli cpan] (http://www.cpan.org/modules/INSTALL.html)? O hai provato a scaricarlo dal sito Web CPAN? Se si utilizza lo strumento della riga di comando, verranno installate tutte le dipendenze. – simbabque

3

È possibile installare GPXpy

sudo pip install gpxpy 

Poi basta utilizzare la libreria:

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

Per maggiori informazioni: https://pypi.python.org/pypi/gpxpy

saluti

Problemi correlati