commit a5f74715484bab5837ffb76a110991354983080d
Author: tkl
Date: Tue Aug 22 23:02:31 2017 +0200
gpx-parser: parser implemented
Also gpx2html script added.
Signed-off-by: Thomas Klaehn
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..adbb97d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+data/
\ No newline at end of file
diff --git a/.vscode/tags b/.vscode/tags
new file mode 100644
index 0000000..ca282b4
--- /dev/null
+++ b/.vscode/tags
@@ -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
diff --git a/example-gpx-parser b/example-gpx-parser
new file mode 100755
index 0000000..9872568
--- /dev/null
+++ b/example-gpx-parser
@@ -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())
diff --git a/gpx2html b/gpx2html
new file mode 100755
index 0000000..eff2fc7
--- /dev/null
+++ b/gpx2html
@@ -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('\n')
+ handle.write('\n')
+ handle.write('\n')
+ handle.write('\n')
+ handle.write(' Bicycle \n')
+ handle.write('\n')
+ handle.write('\n')
+ handle.write('\n')
+ handle.write(' Bicycle
\n')
+ handle.write('\n')
+
+ handle.write('
\n')
+ handle.write('\n')
+ for year in years:
+ handle.write('{} | \n'.format(year))
+ handle.write('
\n')
+
+ handle.write('\n')
+ for i in range(len(years_distance)):
+ handle.write('{} km | \n'.format(round(sum(years_distance[i]), 1)))
+ handle.write('
\n')
+ handle.write('
\n')
+
+ handle.write('
\n')
+
+ handle.write('\n')
+ handle.write('\n'.format(dst_file_name))
+ handle.write('\n'.format(avg_file_name))
+ handle.write('
\n')
+
+ handle.write('\n')
+ handle.write('\n')
+ handle.write('\n')
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/gpx_parser/__init__.py b/gpx_parser/__init__.py
new file mode 100644
index 0000000..d028920
--- /dev/null
+++ b/gpx_parser/__init__.py
@@ -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
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..81b92c2
--- /dev/null
+++ b/setup.py
@@ -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)