gpx-parser: parser implemented
Also gpx2html script added. Signed-off-by: Thomas Klaehn <thomas.klaehn@u-blox.com>
This commit is contained in:
commit
a5f7471548
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
data/
|
8
.vscode/tags
vendored
Normal file
8
.vscode/tags
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||||
|
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||||
|
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||||
|
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||||
|
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||||
|
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||||
|
main ../parse.py /^def main():$/;" kind:function line:3
|
||||||
|
parse.py ../parse.py 1;" kind:file line:1
|
51
example-gpx-parser
Executable file
51
example-gpx-parser
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
import gpx_parser
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
'''Shell argument parser.'''
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('infolder', help='Specify the in folder.')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
tracks = gpx_parser.Tracks(args.infolder)
|
||||||
|
for year in range(2017, 2019):
|
||||||
|
year_distance = 0.0
|
||||||
|
year_duration = 0
|
||||||
|
for month in range(1, 13):
|
||||||
|
if month == 12:
|
||||||
|
max_day = (datetime.date(year + 1, 1, 1) - datetime.timedelta(days=1)).day
|
||||||
|
else:
|
||||||
|
max_day = (datetime.date(year, month + 1, 1) - datetime.timedelta(days=1)).day
|
||||||
|
for day in range(1, max_day):
|
||||||
|
date_tracks = tracks.get(year, month, day)
|
||||||
|
date_date = datetime.datetime(year, month, day)
|
||||||
|
date_dist = 0.0
|
||||||
|
date_duration = 0
|
||||||
|
for track in date_tracks:
|
||||||
|
date_dist += track.distance
|
||||||
|
year_distance += track.distance
|
||||||
|
date_duration += track.duration.total_seconds()
|
||||||
|
year_duration += track.duration.total_seconds()
|
||||||
|
if date_dist > 0.0:
|
||||||
|
print date_date
|
||||||
|
print ' Distance: ' + str(round(date_dist / 1000, 2)) + ' km'
|
||||||
|
print ' Duration: ' + str(datetime.timedelta(seconds=int(round(date_duration, 0))))
|
||||||
|
print 'Average speed: ' + str(round(date_dist / date_duration * 3.6, 2)) + ' km/h'
|
||||||
|
print '=================='
|
||||||
|
print year
|
||||||
|
print ' Distance: ' + str(round(year_distance / 1000, 2)) + ' km'
|
||||||
|
print ' Duration: ' + str(datetime.timedelta(seconds=int(round(year_duration, 0))))
|
||||||
|
print 'Average speed: ' + str(round(year_distance / year_duration * 3.6, 2)) + ' km/h'
|
||||||
|
print '=================='
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
126
gpx2html
Executable file
126
gpx2html
Executable file
@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
import gpx_parser
|
||||||
|
import matplotlib
|
||||||
|
matplotlib.use('Agg')
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy
|
||||||
|
import os
|
||||||
|
|
||||||
|
MONTH_LABELS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
'''Shell argument parser.'''
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('infolder', help='Specify the in folder.')
|
||||||
|
parser.add_argument('outfolder', help='Specify the out folder.')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def plot_bar_chart(labels, ticklabels, values, title, xlabel, ylabel, filename):
|
||||||
|
fig = plt.figure()
|
||||||
|
ax1 = fig.add_subplot(111)
|
||||||
|
ax1.grid(zorder=0)
|
||||||
|
|
||||||
|
plt.title(title)
|
||||||
|
plt.xlabel(xlabel)
|
||||||
|
plt.ylabel(ylabel)
|
||||||
|
|
||||||
|
width = 1.0 / len(values) - 0.025
|
||||||
|
x_base = numpy.arange(12)
|
||||||
|
x_pos = list()
|
||||||
|
|
||||||
|
for i in range(len(values)):
|
||||||
|
x_pos.append([x + (width / 2) + i * width for x in range(len(x_base))])
|
||||||
|
plt.bar(x_pos[i], values[i], width=width, label=labels[i], zorder=2)
|
||||||
|
|
||||||
|
plt.xticks(x_base, ticklabels)
|
||||||
|
plt.legend()
|
||||||
|
plt.savefig(filename)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_args()
|
||||||
|
tracks = gpx_parser.Tracks(args.infolder)
|
||||||
|
years_distance = list()
|
||||||
|
years_avg_spd = list()
|
||||||
|
years = list()
|
||||||
|
for year in range(2017, datetime.datetime.now().year + 1):
|
||||||
|
month_avg_spd = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0}
|
||||||
|
month_distance = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0}
|
||||||
|
month_duration = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0}
|
||||||
|
for month in range(1, 13):
|
||||||
|
if month == 12:
|
||||||
|
max_day = (datetime.date(year + 1, 1, 1) - datetime.timedelta(days=1)).day
|
||||||
|
else:
|
||||||
|
max_day = (datetime.date(year, month + 1, 1) - datetime.timedelta(days=1)).day
|
||||||
|
for day in range(1, max_day):
|
||||||
|
date_tracks = tracks.get(year, month, day)
|
||||||
|
for track in date_tracks:
|
||||||
|
month_distance[month] += (track.distance / 1000) # km
|
||||||
|
month_duration[month] += track.duration.total_seconds() / 3600 # h
|
||||||
|
for i in range(1, 13):
|
||||||
|
if month_duration[i] > 0:
|
||||||
|
month_avg_spd[i] = month_distance[i] / month_duration[i]
|
||||||
|
years_distance.append(month_distance.values())
|
||||||
|
years_avg_spd.append(month_avg_spd.values())
|
||||||
|
years.append(str(year))
|
||||||
|
|
||||||
|
out_folder = os.path.abspath(args.outfolder)
|
||||||
|
|
||||||
|
dst_file_name = 'distance.png'
|
||||||
|
plot_bar_chart(years, MONTH_LABELS, years_distance, 'Distance', 'Month', 'km', os.path.join(out_folder, dst_file_name))
|
||||||
|
|
||||||
|
avg_file_name = 'avg_spd.png'
|
||||||
|
plot_bar_chart(years, MONTH_LABELS, years_avg_spd, 'Average Speed', 'Month', 'km/h', os.path.join(out_folder, avg_file_name))
|
||||||
|
|
||||||
|
html_file = os.path.join(out_folder, 'index.html')
|
||||||
|
with open(html_file, 'w') as handle:
|
||||||
|
handle.write('<!DOCTYPE html>\n')
|
||||||
|
handle.write('<html>\n')
|
||||||
|
handle.write('<head>\n')
|
||||||
|
handle.write('<style>\n')
|
||||||
|
handle.write('table {\n')
|
||||||
|
handle.write(' border-collapse: separate;\n')
|
||||||
|
handle.write(' border-spacing: 20px 0;\n')
|
||||||
|
handle.write('}\n')
|
||||||
|
handle.write('th {\n')
|
||||||
|
handle.write(' text-align: left;\n')
|
||||||
|
handle.write('}\n')
|
||||||
|
handle.write('</style>\n')
|
||||||
|
handle.write('<title> Bicycle </title>\n')
|
||||||
|
handle.write('</head>\n')
|
||||||
|
handle.write('<body>\n')
|
||||||
|
handle.write('<center>\n')
|
||||||
|
handle.write('<h1> Bicycle </h1>\n')
|
||||||
|
handle.write('<p>\n')
|
||||||
|
|
||||||
|
handle.write('<table>\n')
|
||||||
|
handle.write('<tr>\n')
|
||||||
|
for year in years:
|
||||||
|
handle.write('<th>{}</th>\n'.format(year))
|
||||||
|
handle.write('</tr>\n')
|
||||||
|
|
||||||
|
handle.write('<tr>\n')
|
||||||
|
for i in range(len(years_distance)):
|
||||||
|
handle.write('<td>{} km</td>\n'.format(round(sum(years_distance[i]), 1)))
|
||||||
|
handle.write('</tr>\n')
|
||||||
|
handle.write('</table>\n')
|
||||||
|
|
||||||
|
handle.write('</p>\n')
|
||||||
|
|
||||||
|
handle.write('<p>\n')
|
||||||
|
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format(dst_file_name))
|
||||||
|
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format(avg_file_name))
|
||||||
|
handle.write('</p>\n')
|
||||||
|
|
||||||
|
handle.write('</body>\n')
|
||||||
|
handle.write('<center>\n')
|
||||||
|
handle.write('</html>\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
82
gpx_parser/__init__.py
Normal file
82
gpx_parser/__init__.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import datetime
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import gpxpy
|
||||||
|
import gpxpy.gpx
|
||||||
|
from geopy import distance
|
||||||
|
from geopy import Point
|
||||||
|
|
||||||
|
class Segment(object):
|
||||||
|
start_time = None
|
||||||
|
end_time = None
|
||||||
|
distance = 0.0 # [m]
|
||||||
|
|
||||||
|
class Track(object):
|
||||||
|
start_time = None
|
||||||
|
end_time = None
|
||||||
|
distance = 0.0 # [m]
|
||||||
|
avg_speed = 0.0 # [km/h]
|
||||||
|
duration = None
|
||||||
|
|
||||||
|
def __init__(self, raw_track):
|
||||||
|
self.__raw = raw_track
|
||||||
|
for segment in self.__raw.segments:
|
||||||
|
seg = Segment()
|
||||||
|
for i in range(1, len(segment.points)):
|
||||||
|
if self.start_time is None:
|
||||||
|
self.start_time = segment.points[i - 1].time
|
||||||
|
if seg.start_time is None:
|
||||||
|
seg.start_time = segment.points[i - 1].time
|
||||||
|
seg.end_time = segment.points[i - 1].time
|
||||||
|
point1 = Point(str(segment.points[i - 1].latitude) + \
|
||||||
|
' ' + str(segment.points[i - 1].longitude))
|
||||||
|
point2 = Point(str(segment.points[i].latitude) + \
|
||||||
|
' ' + str(segment.points[i].longitude))
|
||||||
|
seg.distance += distance.distance(point1, point2).meters
|
||||||
|
|
||||||
|
if self.duration is None:
|
||||||
|
self.duration = seg.end_time - seg.start_time
|
||||||
|
else:
|
||||||
|
self.duration += seg.end_time - seg.start_time
|
||||||
|
self.end_time = seg.end_time
|
||||||
|
self.distance += seg.distance
|
||||||
|
self.avg_speed = self.distance / self.duration.total_seconds() * 3.6
|
||||||
|
|
||||||
|
|
||||||
|
class Tracks(object):
|
||||||
|
track_list = None
|
||||||
|
|
||||||
|
def __init__(self, folder):
|
||||||
|
self.track_list = list()
|
||||||
|
gpx_list = glob.glob(os.path.join(folder, '*.gpx'))
|
||||||
|
for entry in gpx_list:
|
||||||
|
with open(entry, 'r') as gpx_handle:
|
||||||
|
gpx = gpxpy.parse(gpx_handle)
|
||||||
|
for raw_track in gpx.tracks:
|
||||||
|
self.track_list.append(Track(raw_track))
|
||||||
|
|
||||||
|
def get(self, year='all', month='all', day='all'):
|
||||||
|
ret = list()
|
||||||
|
if year == 'all':
|
||||||
|
ret = self.track_list
|
||||||
|
elif month == 'all':
|
||||||
|
pick_date = datetime.datetime(year=year, month=1, day=1)
|
||||||
|
for entry in self.track_list:
|
||||||
|
if pick_date.year == entry.start_time.year:
|
||||||
|
ret.append(entry)
|
||||||
|
elif day == 'all':
|
||||||
|
pick_date = datetime.datetime(year=year, month=month, day=1)
|
||||||
|
ret = list()
|
||||||
|
for entry in self.track_list:
|
||||||
|
if pick_date.year == entry.start_time.year and \
|
||||||
|
pick_date.month == entry.start_time.month:
|
||||||
|
ret.append(entry)
|
||||||
|
else:
|
||||||
|
pick_date = datetime.datetime(year=year, month=month, day=day)
|
||||||
|
ret = list()
|
||||||
|
for entry in self.track_list:
|
||||||
|
if pick_date.year == entry.start_time.year and \
|
||||||
|
pick_date.month == entry.start_time.month and \
|
||||||
|
pick_date.day == entry.start_time.day:
|
||||||
|
ret.append(entry)
|
||||||
|
return ret
|
12
setup.py
Executable file
12
setup.py
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
NAME = 'gpx_parser'
|
||||||
|
VERSION = '0.2.0'
|
||||||
|
AUTHOR = 'Thomas Klaehn'
|
||||||
|
EMAIL = 'tkl@blackfinn.de'
|
||||||
|
PACKAGES = [NAME]
|
||||||
|
SCRIPTS = ['example-gpx-parser', 'gpx2html']
|
||||||
|
|
||||||
|
setup(name=NAME, version=VERSION, author=AUTHOR, author_email=EMAIL, packages=PACKAGES, scripts=SCRIPTS)
|
Loading…
Reference in New Issue
Block a user