bicycle_statistics: Update pages differentially

Signed-off-by: Thomas Klaehn <thomas.klaehn@u-blox.com>
This commit is contained in:
Thomas Klaehn
2018-09-05 23:39:54 +02:00
parent 629794d5f2
commit 102642d4ba
4 changed files with 167 additions and 157 deletions

View File

@@ -2,6 +2,7 @@
import argparse
import datetime
import glob
import sys
import gpx_parser
import matplotlib
@@ -11,6 +12,10 @@ import numpy
import os
import pandas as pd
import collections
from gpx_parser import Tracks
MONTH_LABELS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
def plot_bar_chart(labels, ticklabels, values, title, xlabel, ylabel, filename, xtick_rotation=0):
fig = plt.figure()
@@ -41,43 +46,103 @@ def plot_bar_chart(labels, ticklabels, values, title, xlabel, ylabel, filename,
plt.legend()
plt.savefig(filename)
class Gpx2Html(object):
MONTH_LABELS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
def __init__(self, infolder, outfolder):
def __init__(self, infolder, outfolder, logger):
self.logger = logger
self.infolder = infolder
self.outfolder = os.path.abspath(outfolder)
self.distance_diag_file = 'distance.png'
self.distance_diag_abs = os.path.join(self.outfolder, self.distance_diag_file)
self.avg_spd_diag_file = 'avg_spd.png'
self.avg_spd_diag_abs = os.path.join(self.outfolder, self.avg_spd_diag_file)
self.last_n_days_diag_file = None
self.html_file = os.path.join(self.outfolder, 'index.html')
self.years_distance = list()
self.years_avg_spd = list()
self.years = list()
self.tracks = Tracks(logger)
self.update()
def plot_distance_diagram(self):
plot_bar_chart(self.years, self.MONTH_LABELS, self.years_distance,
'Distance', 'Month', 'km', self.distance_diag_abs)
def update(self):
infiles = glob.glob(os.path.join(self.infolder, '*.gpx'))
for filename in infiles:
self.tracks.add(filename)
self.logger.info("Begin update of png's/html...")
distances = list()
avg_speeds = list()
for year in self.tracks.years():
distances.append(self.tracks.distances(year))
avg_speeds.append(self.tracks.avg_speeds(year))
def plot_avg_spd_diagram(self):
plot_bar_chart(self.years, self.MONTH_LABELS, self.years_avg_spd,
'Average Speed', 'Month', 'km/h', self.avg_spd_diag_abs)
plot_bar_chart(self.tracks.years(), MONTH_LABELS, distances,
'Distance', 'Month', 'km',
os.path.join(self.outfolder, 'distance.png'))
plot_bar_chart(self.tracks.years(), MONTH_LABELS, avg_speeds,
'Average Speed', 'Month', 'km/h',
os.path.join(self.outfolder, 'avg_spd.png'))
def plot_last_n_days(self, day_count):
plot_bar_chart(["Distance", "Average speed"], self.date_distance.keys(),
[self.date_distance.values(), self.date_avg_spd.values()],
'Last {} days'.format(day_count), 'Date', 'km, km/h',
os.path.join(self.outfolder, self.last_n_days_diag_file), 90)
end_date = datetime.datetime.today()
start_date = end_date - datetime.timedelta(days=14)
last_n_tracks = self.tracks.tracks(start_date, end_date)
last_n_distances = dict()
last_n_durations = dict()
dates = pd.date_range(start_date.date(), end_date.date())
for date in dates:
for track in last_n_tracks:
if date.date() == track.start_time.date():
get = 0
try:
get = last_n_distances[date.date()]
except KeyError:
pass
if get == 0:
last_n_distances[date.date()] = track.distance / 1000
else:
last_n_distances[date.date()] += track.distance / 1000
try:
get = last_n_durations[date.date()]
except KeyError:
pass
if get == 0:
last_n_durations[date.date()] = track.duration.total_seconds()
else:
last_n_durations[date.date()] += track.duration.total_seconds()
else:
try:
get = last_n_distances[date.date()]
except KeyError:
last_n_distances[date.date()] = 0
try:
get = last_n_durations[date.date()]
except KeyError:
last_n_durations[date.date()] = 0
last_n_dist = list()
last_n_dur = list()
last_n_avg = list()
last_n_dates = list()
for date in dates:
try:
last_n_dist.append(last_n_distances[date.date()])
except KeyError:
last_n_dist.append(0)
try:
last_n_dur.append(last_n_durations[date.date()])
except KeyError:
last_n_dur.append(0)
date_str = "{0:04d}-{1:02d}-{2:02d}".format(date.year, date.month, date.day)
last_n_dates.append(date_str)
try:
if last_n_durations[date.date()] == 0:
last_n_avg.append(0)
else:
last_n_avg.append(last_n_distances[date.date()] /
(last_n_durations[date.date()] / 3600))
except KeyError:
last_n_avg.append(0)
plot_bar_chart(["Distance", "Average speed"], last_n_dates,
[last_n_dist, last_n_avg],
'Last 14 days', 'Date', 'km, km/h',
os.path.join(self.outfolder, 'last_14_days.png'), 90)
self.__write_html_file()
self.logger.info("End update of png's/html...")
def write_html_file(self):
with open(self.html_file, 'w') as handle:
def __write_html_file(self):
with open(os.path.join(self.outfolder, 'index.html'), 'w') as handle:
handle.write('<!DOCTYPE html>\n')
handle.write('<html>\n')
handle.write('<head>\n')
@@ -99,102 +164,24 @@ class Gpx2Html(object):
handle.write('<table>\n')
handle.write('<tr>\n')
for year in self.years:
for year in self.tracks.years():
handle.write('<th>{}</th>\n'.format(year))
handle.write('</tr>\n')
handle.write('<tr>\n')
for i in range(len(self.years_distance)):
handle.write('<td>{} km</td>\n'.format(round(sum(self.years_distance[i]), 1)))
for year in self.tracks.years():
handle.write('<td>{} km</td>\n'.format(round(sum(self.tracks.distances(year)), 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(self.distance_diag_file))
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format(self.avg_spd_diag_file))
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format(self.last_n_days_diag_file))
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('distance.png'))
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('avg_spd.png'))
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('last_14_days.png'))
handle.write('</p>\n')
handle.write('</body>\n')
handle.write('<center>\n')
handle.write('</html>\n')
def process(self):
self.years[:] = []
self.years_avg_spd[:] = []
self.years_distance[:] = []
self.tracks = gpx_parser.Tracks(self.infolder)
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 + 1):
date_tracks = self.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]
self.years_distance.append(month_distance.values())
self.years_avg_spd.append(month_avg_spd.values())
self.years.append(str(year))
self.plot_distance_diagram()
self.plot_avg_spd_diagram()
# last n days
n = 14
end_date = datetime.date.today()
start_date = end_date - datetime.timedelta(days=n)
dates = pd.date_range(start_date, end_date)
self.date_distance = dict()
date_duration = dict()
self.date_avg_spd = dict()
for date in dates:
date_str = "{0:04d}-{1:02d}-{2:02d}".format(date.year, date.month, date.day)
date_tracks = self.tracks.get(date.year, date.month, date.day)
for track in date_tracks:
try:
current_dist = self.date_distance[date_str]
current_duration = date_duration[date_str]
except KeyError:
current_dist = 0
current_duration = 0
current_dist += track.distance / 1000
self.date_distance.update({date_str:current_dist})
current_duration += track.duration.total_seconds() / 3600
date_duration.update({date_str:current_duration})
# check for empty dates
try:
current_dist = self.date_distance[date_str]
current_duration = date_duration[date_str]
except KeyError:
self.date_distance.update({date_str:0})
date_duration.update({date_str:0})
date_duration = collections.OrderedDict(sorted(date_duration.items()))
for key, value in date_duration.items():
if value == 0:
self.date_avg_spd.update({key:0})
else:
avg_spd = self.date_distance[key] / value
self.date_avg_spd.update({key:avg_spd})
self.date_avg_spd = collections.OrderedDict(sorted(self.date_avg_spd.items()))
self.date_distance = collections.OrderedDict(sorted(self.date_distance.items()))
self.last_n_days_diag_file = "distance_last_{}_days.png".format(n)
self.plot_last_n_days(n)
self.write_html_file()