Seite 1 von 1
GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 17:37
von Strawk
Hallo Leute!
Eine GPX-Datei enthält pro trackpoint auch die jeweilige Höhe. Ziel, ermitteln: Wie weit wurde jeweils hochgegangen, und wie weit jeweils runter? Folgender Code ist falsch:
Code: Alles auswählen
def up_down_hill(self):
"""
comment ...
"""
df = self.df
maxTrkPoints = df.shape[0]
upHill = 0
downHill = 0
for i in range(1, maxTrkPoints-1):
if df['alt'][i] > df['alt'][i+1]:
upHill = upHill + (df['alt'][i+1] - df['alt'][i])
if df['alt'][i] < df['alt'][i+1]:
downHill = downHill + (df['alt'][i+1] - df['alt'][i])
return upHill, downHill
Wie muss er richtig lauten?
Strawk
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 17:52
von Sirius3
@Strawk: wenn Du weißt, dass es falsch ist, was ist genau daran falsch?
Du benutzt anscheinend numpy. Da ist das Berechnen von up_hill und down_hill, ein Einzeiler, ohne Schleife:
Code: Alles auswählen
delta = np.diff(self.df)
up_hill = numpy.maximum(delta, 0).sum()
down_hill = numpy.minimum(delta, 0).sum()
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 17:58
von Strawk
Hallo Sirius3, falsch ist daran, dass er falsche Ergebnisse liefert. S.
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 18:02
von Sirius3
Aber woher weißt Du, dass es falsche Ergebnisse liefert, poste Beispieldaten mit Ergebnis und erwartetem Ergebnis.
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 18:12
von Strawk
Ich weiß das daher, weil ein Freund (Berufsprogrammierer) andere Ergebnise hat. Und weil die Addition nicht der Gesamthöhendifferenz entsprach. Ich habe jetzt die größer, kleiner Zeichen getauscht und die Schleife bei 0 statt bei 1 beginnen lassen ... passt!
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 18:23
von Sirius3
Ja, die i+1 hab ich übersehen, weil das ja so niemand auch macht. Nimm das, was numpy sowieso schon bietet. Vielleicht fruchtet das ja beim siebten mal, dass ich das schreibe.
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 18:27
von Strawk
Hallo Sirius3!
Keine Sorge, das hat schon beim ersten Mal 'gefruchtet'. Das kollidiert nur etwas mit meinem Ehrgeiz: selber machen, anstatt einfach die numpy-Funktionalität zu übernehmen. Vernünftig ist das nicht; ich weiß.
Strawk
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 18:34
von Sirius3
Das hat nichts mit selber machen zu tun, weil dann müßtest Du damit anfangen, Bits hin und her zu schupsen. Programmieren bedeutet, die richtigen Mittel einzusetzen, um ein Problem so einfach wie möglich zu lösen.
Re: GPX downHill upHill berechnen
Verfasst: Sonntag 20. Januar 2019, 20:30
von Strawk
Hallo Sirius3,
hast ja recht.

Apropos: Kannst du mir deinen Code etwas erklären? Du schreibst sowohl np, als auch numpy. Mein Skript importiert so: import numpy as np. Wie muss ich den Code anpassen; er läuft bei mir noch nicht. Ich bekomme: delta = np.diff(self.df), TypeError: unsupported operand type(s) for -: 'Timestamp' and 'float'
Grüße, Strawk
Code komplett hier:
Code: Alles auswählen
# -*- coding: utf-8 -*-
"""
Created on Fri Jan 4 16:43:18 2019
@author: Karl Kraft
"""
from __future__ import print_function, division
import gpxpy
import pandas as pd
from geopy import distance
import matplotlib.pyplot as plt
import numpy as np
import numpy
import time
from glob import glob
class Trajectory():
def __init__(self, gpxdata):
"""
constructor, creates dataframe
"""
self.gpx = gpxdata
# initiation of booleans for properties of different types of gpx-files
self.has_tracks = False
self.has_routes = False
self.has_elevation = False
self.has_time = False
if gpxdata.routes:
self.has_routes = True
if gpxdata.tracks:
self.has_tracks = True
if self.has_tracks == True:
if gpxdata.tracks[0].segments[0].points[0].elevation:
self.has_elevation = True
if gpxdata.tracks[0].segments[0].points[0].time:
self.has_time = True
data = gpxdata.tracks[0].segments[0].points
df = []
self.df = pd.DataFrame()
pts = gpxdata.tracks[0].segments[0].points
self.df['lon'] = [pt.longitude for pt in pts]
self.df['lat'] = [pt.latitude for pt in pts]
# different cases of having altitude- and/or time-information
if self.has_elevation:
self.df['alt'] = [pt.elevation for pt in pts]
if self.has_time:
self.df['time'] = [pt.time for pt in pts]
else:
data = gpxdata.routes[0].points
df = []
for point in data:
df.append({'lon': point.longitude, 'lat' : point.latitude})
self.df = pd.DataFrame(df, columns=['lon', 'lat'])
# public methods
def total_distance(self):
"""
Calculates the total distance of a list of geographic points
Input: list of geographic points [(lat1,lon1), (lat2, lon2), ..., (lat_n, lon_n)]
Output: total distance in km, i.e. d(p2,p1) + d(p3,p2) + .... + d(p_n,p_(n-1)), where d(x,y) is
the distance of points x and y
"""
df = self.df
geopoints = list(zip(df['lat'], df['lon']))
Npoints = len(geopoints)
total_distance = 0
for i in range(1,Npoints):
total_distance += distance.distance(geopoints[i], geopoints[i-1]).m
return total_distance
def start_end_elevation(self):
"""
calculates the altitude at the beginning and at the end of a whole trip
"""
Npoints = self.df.shape[0]
startElev = self.df['alt'][0]
endElev = self.df['alt'][Npoints-1]
return startElev, endElev
def min_max_elevation(self):
"""
calculates the minimum and maximum altitude of a whole trip
"""
minElev = self.df['alt'].min()
maxElev = self.df['alt'].max()
return minElev, maxElev
def up_down_hill(self):
"""
calculates the total uphill and downhill movement
"""
'''
df = self.df
maxTrkPoints = df.shape[0]
upHill = 0
downHill = 0
for i in range(0, maxTrkPoints-1):
if df['alt'][i] < df['alt'][i+1]:
upHill = upHill + (df['alt'][i+1] - df['alt'][i])
if df['alt'][i] > df['alt'][i+1]:
downHill = downHill + (df['alt'][i+1] - df['alt'][i])
return upHill, downHill
'''
delta = np.diff(self.df)
up_hill = numpy.maximum(delta, 0).sum()
down_hill = numpy.minimum(delta, 0).sum()
return up_hill, down_hill
def total_elapsed_time(self):
"""
calculates the total time elapsed of the track walked
"""
Npoints = self.df.shape[0]
# print(Npoints)
startTime = self.df['time'][0]
endTime = self.df['time'][Npoints-1]
total_elapsed_time = endTime - startTime
return total_elapsed_time
def plot_velocities(self):
"""
creates a graphical plot of all velocities between each of the two trackpoints
"""
lstVelocities = self.__create_velocities()
lstDistancesAddedTogether = self.__distances_cumul_sum()
plt.plot(lstDistancesAddedTogether, lstVelocities)
plt.xlabel('Distance [km]')
plt.ylabel('Velocity [km/h]')
plt.show()
def plot_trip(self, gpxdata):
"""
creates a graphical plot of the whole trip
"""
# data = gpxdata.tracks[0].segments[0].points
df = pd.DataFrame()
if self.has_tracks:
pts = gpxdata.tracks[0].segments[0].points
if self.has_routes:
pts = gpxdata.routes[0].points
df['lon'] = [pt.longitude for pt in pts]
df['lat'] = [pt.latitude for pt in pts]
plt.plot(df['lon'], df['lat'])
plt.show()
def print_summary(self):
total_distance = self.total_distance()
print('Total distance: {:.3f}'.format(total_distance/1000), 'kilometer')
if self.has_time:
total_elapsed_time = self.total_elapsed_time()
print('Total elapsed time:', total_elapsed_time, 'hh:mm:ss')
else:
print("time and velocity not available")
if self.has_elevation:
startEndElevation = self.start_end_elevation()
minMaxElevation = self.min_max_elevation()
upDownHill = self.up_down_hill()
print('start/end elevation m:', startEndElevation)
print('min/max elevation m:', minMaxElevation)
print('up/down hill m:', upDownHill)
else:
print("elevation-infos not available")
# private methods
def __create_distances(self):
"""
all single distances are calculated, necessary for velocity-calculation
"""
df = self.df
maxTrkPoints = df.shape[0]
return [distance.distance((df['lat'][i], df['lon'][i]), (df['lat'][i+1], df['lon'][i+1])).km for i in range(1, maxTrkPoints-1)]
def __create_velocities(self):
"""
creates a list of all velocities based on seconds and appropriate distances
"""
lstSeconds = self.__create_seconds()
lstDistances = self.__create_distances()
Npoints = self.df.shape[0]
return [((lstDistances[i]*1000) / lstSeconds[i]*3.6) for i in range(0, Npoints-2)]
def __create_seconds(self):
"""
all single seconds are calculated, necessary for velocity-calculation
"""
maxTrkPoints = self.df.shape[0]
if self.has_time:
lstSeconds = []
for i in range(0, maxTrkPoints):
t = self.df['time'][i]
lstSeconds.append(time.mktime(t.timetuple()))
else:
raise Exception("time not available")
lstTimeDifferenceSeconds = []
for i in range(1, maxTrkPoints-1):
timeDifference = lstSeconds[i+1] - lstSeconds[i]
lstTimeDifferenceSeconds.append(timeDifference)
return lstTimeDifferenceSeconds
def __distances_cumul_sum(self):
"""
creates distance values by using the cumulative sum of all distances
"""
lstDistances = self.__create_distances()
return np.cumsum(lstDistances)
class TrackCount():
"""
help functions, count elements only
"""
def __init__(self, gpxdata):
self.gpx = gpxdata
def count_tracks(self):
return len(self.gpx.tracks)
def count_segments(self):
nSegments = 0
for track in self.gpx.tracks:
for segment in track.segments:
nSegments+=1
return nSegments
def count_points(self):
nTrackpoints = 0
for track in self.gpx.tracks:
for segment in track.segments:
for point in segment.points:
nTrackpoints +=1
return nTrackpoints
class WaypointCount():
"""
help functions, count elements only
"""
def __init__(self, gpxdata):
self.gpx = gpxdata
def count_waypoints(self):
return len(self.gpx.waypoints)
class RouteCount():
"""
help functions, count elements only
"""
def __init__(self, gpxdata):
self.gpx = gpxdata
def count_routes(self):
return len(self.gpx.routes)
def count_points(self):
return sum([len(route.points) for route in self.gpx.routes])
def main():
for filename in glob("data/*.gpx"):
with open(filename) as gpx_file:
gpxdata = gpxpy.parse(gpx_file)
# help class TrackCount and its methods, instantiating an object
myTrackCount = TrackCount(gpxdata)
nTracks = myTrackCount.count_tracks()
nSegments = myTrackCount.count_segments()
nTrackpoints = myTrackCount.count_points()
# help class WaypointCount and its methods, instantiating an object
myWaypointCount = WaypointCount(gpxdata)
nWaypoints = myWaypointCount.count_waypoints()
# help class RouteCount and its methods, instantiating an object
myRouteCount = RouteCount(gpxdata)
nRoutes = myRouteCount.count_routes()
nPoints = myRouteCount.count_points()
if (nTracks == 1 and nSegments == 1 and nTrackpoints >= 1) or (nRoutes >= 1 and nPoints >=1):
pass
else:
raise TypeError("unexpected file")
print()
print("results for:", filename)
mytrack = Trajectory(gpxdata)
mytrack.print_summary()
if mytrack.has_time:
mytrack.plot_velocities()
mytrack.plot_trip(gpxdata)
'''
if mytrack.has_elevation:
# mytrack.start_end_elevation()
# mytrack.min_max_elevation()
# mytrack.up_down_hill()
pass
'''
if __name__ == "__main__":
tbegin = time.clock()
main()
computation_time = time.clock()-tbegin
print("Executing the script took %6.3f seconds" % (computation_time))
Re: GPX downHill upHill berechnen
Verfasst: Mittwoch 23. Januar 2019, 21:53
von Sirius3
__init__ ist kein Konstruktor, und sondern in Initialisierer. Man prüft nicht explizit auf == True.
Variablen werden klein_mit_unterstrich geschrieben. Npoints ist überflüssig, da man auch mit -1 von hinten her indizieren kann.
Warum benutzt total_distance nicht create_distances?
Es gibt keine privaten Methoden, die doppelten Unterstriche sind damit auch falsch.
In plot_trip gibt es einen NameError, wenn weder has_tracks noch has_routes True sind.
Warum erzeugst Du in `plot_trip` den Dataframe nochmal?
Die ganzen Hilfsklassen sind irgendwie überflüssig. Entweder funktioniert das Lesen, oder es gibt an der passenden Stelle einen Fehler automatisch.
Ungetestet:
Code: Alles auswählen
from __future__ import print_function, division
from glob import glob
import matplotlib.pyplot as plt
import pandas as pd
from geopy import distance
import gpxpy
class Trajectory():
def __init__(self, gpxdata):
"""
initializes dataframe
"""
self.gpx = gpxdata
# initiation of booleans for properties of different types of gpx-files
self.has_tracks = bool(gpxdata.tracks)
self.has_routes = bool(gpxdata.routes)
self.has_elevation = False
self.has_time = False
if self.has_tracks:
self.points = gpxdata.tracks[0].segments[0].points
self.has_elevation = bool(self.points[0].elevation)
self.has_time = bool(self.points[0].time)
else:
self.points = gpxdata.routes[0].points
self.has_elevation = False
self.has_time = False
self.df = pd.DataFrame()
self.df['lon'] = [pt.longitude for pt in self.points]
self.df['lat'] = [pt.latitude for pt in self.points]
# different cases of having altitude- and/or time-information
if self.has_elevation:
self.df['alt'] = [pt.elevation for pt in self.points]
if self.has_time:
self.df['time'] = [pt.time for pt in self.points]
# public methods
@property
def total_distance(self):
"""
Calculates the total distance of a list of geographic points
Input: list of geographic points [(lat1,lon1), (lat2, lon2), ..., (lat_n, lon_n)]
Output: total distance in km, i.e. d(p2,p1) + d(p3,p2) + .... + d(p_n,p_(n-1)), where d(x,y) is
the distance of points x and y
"""
return self.get_distances().sum()
@property
def start_end_elevation(self):
"""
calculates the altitude at the beginning and at the end of a whole trip
"""
alt = self.df['alt']
return alt[0], alt[-1]
@property
def min_max_elevation(self):
"""
calculates the minimum and maximum altitude of a whole trip
"""
alt = self.df['alt']
return alt.min(), alt.max()
@property
def up_down_hill(self):
"""
calculates the total uphill and downhill movement
"""
delta = self.df['alt'].diff()
up_hill = diff.clip_lower(0).sum()
down_hill = diff.clip_upper(0).sum()
return up_hill, down_hill
@property
def total_elapsed_time(self):
"""
calculates the total time elapsed of the track walked
"""
time = self.df['time']
return time[-1] - time[0]
def plot_velocities(self):
"""
creates a graphical plot of all velocities between each of the two trackpoints
"""
distances = self.get_distances()
seconds = self.df['time'].diff()[1:].dt.total_seconds()
velocities = distance/seconds / 3.6
plt.plot(distances.cumsum(), velocities)
plt.xlabel('Distance [km]')
plt.ylabel('Velocity [km/h]')
plt.show()
def plot_trip(self):
"""
creates a graphical plot of the whole trip
"""
plt.plot(self.df['lon'], self.df['lat'])
plt.show()
def print_summary(self):
print('Total distance: {:.3f}'.format(self.total_distance/1000), 'kilometer')
if self.has_time:
print('Total elapsed time:', self.total_elapsed_time, 'hh:mm:ss')
else:
print("time and velocity not available")
if self.has_elevation:
print('start/end elevation m:', self.start_end_elevation)
print('min/max elevation m:', self.min_max_elevation)
print('up/down hill m:', self.up_down_hill)
else:
print("elevation-infos not available")
# private methods
def get_distances(self):
"""
all single distances are calculated in meters, necessary for velocity-calculation
"""
rows = df[['lat','lon']].iterrows()
first = next(rows)
distances = []
for second in rows:
distances.append(
distance.distance(first, second).m
)
first = second
return pd.Series(distances)
def get_velocities(self):
"""
creates a list of all velocities in km/h based on seconds and appropriate distances
"""
distances = self.get_distances()
seconds = self.df['time'].diff()[1:].dt.total_seconds()
return distance/seconds / 3.6
def main():
for filename in glob("data/*.gpx"):
with open(filename) as gpx_file:
gpxdata = gpxpy.parse(gpx_file)
print("results for:", filename)
trajectory = Trajectory(gpxdata)
trajectory.print_summary()
if trajectory.has_time:
trajectory.plot_velocities()
trajectory.plot_trip()
if __name__ == "__main__":
main()
Re: GPX downHill upHill berechnen
Verfasst: Dienstag 29. Januar 2019, 18:09
von Strawk
Hallo!
Gerne möchte ich eine GPX-Datei richtig einstufen. Mein Programm soll, wenn mehrere Tracks enthalten sind, nur den ersten verwenden/bearbeiten/analysieren. Wenn mehrere Routen enthalten sind, nur die erste Route. Sind weder Tracks, noch Routen enthalten, soll ein Fehler ausgegeben werden. Wie muss der Code lauten, der die Anzahl dieser genannten Elemente erkennt, bzw. wo werde ich dazu fündig?
@sirius3: Das sind sicher wertvolle Tipps. Was die Konventionen betrifft, hat mein Lehrer seine eigenen Vorstellungen, die sich mit deinen nicht immer decken.
Grüße
Strawk
Re: GPX downHill upHill berechnen
Verfasst: Dienstag 29. Januar 2019, 19:57
von Sirius3
Bei Python gibt es keine eigenen Vorstellungen, weil es feste Regeln gibt. Zeige Deinem Lehrer
https://www.python.org/dev/peps/pep-0008/. Da steht alles drin.
Zur Frage: Du mußt gar nichts machen. Wenn mehr als ein Track da ist, werden die anderen sowieso ignoriert. Wenn keiner da ist, dann liefert track[0] einen IndexError, dann ist auch klar, dass kein Track existiert.
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 11:07
von Strawk
Hallo!
Ich bräuchte eine GPX-Datei mit mehreren Tracks und in den Tracks mit mehreren Segmenten. Wo bekomme ich die her? Am besten mehrere Dateien.
Grüße
Strawk

Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 11:17
von __blackjack__
@Strawk: Am einfachsten erzeugst Du Dir die selber. Vorteil ist dann auch, dass Du ganz genau weisst was da drin steht, also zum Beispiel auch die genaue Anzahl an Höhenmetern die darin überwunden wurden.
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 15:46
von Strawk
Hallo!
Ziel: eine verschachtelte Liste. Obere Ebene: tracks. Untere Ebene: points per segment. Habe ich folgendermaßen implementiert:
Code: Alles auswählen
class TrackCount():
"""
help functions, count elements only
"""
def __init__(self, gpxdata):
self.gpx = gpxdata
def count_tracks(self):
return len(self.gpx.tracks)
def count_segments(self):
return sum([len(track.segments) for track in self.gpx.tracks])
def count_points(self):
return sum([sum([len(segment.points) for segment in track.segments]) for track in self.gpx.tracks])
def count_points_nested(self):
"""
returns a nested list with the points per segment
"""
# print(len(self.count_tracks()[0]))
# nTracks = self.count_tracks()
# print(nTracks)
lstTracks = []
lstPointsNested = []
for track in self.gpx.tracks:
for segment in track.segments:
lstPointsNested.append(len(segment.points))
lstTracks.append(lstPointsNested)
return lstTracks
Problem: Statt vier verschiedener Listen, erhalte ich 4x dieselbe Liste.
Tipps?
Grüße
Strawk
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 15:55
von __deets__
List vor der inneren Schleife anlegen. Oder gleich eine list comprehension benutzen, was du wenige Zeilen vorher ja noch beherrschst.
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 15:57
von kbr
@Strawk: schau Dir mal an, wo und wie oft Du lstPointsNested (schlechter Name) anlegst und wo Du diese Liste zu lstTracks (auch kein guter Name) hinzufügst.
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 16:12
von Strawk
Hi!
@_deets_: DANKE!!
Gruß, Strawk
Re: GPX downHill upHill berechnen
Verfasst: Samstag 23. Februar 2019, 16:21
von __blackjack__
@Strawk: Zusätzlich zu den schon gegannten schlechten Namen `count_points_nested()` macht auch nicht das was der Name vermuten lässt. Und warum stecken diese ganzen Funktionen sinnloserweise in einer Klasse?