Compare commits
1 Commits
af1b4ff9d8
...
401be97073
Author | SHA1 | Date | |
---|---|---|---|
|
401be97073 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
build/
|
||||||
*.gpx
|
*.gpx
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
*.pyc
|
*.pyc
|
||||||
|
@ -14,7 +14,7 @@ LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s"
|
|||||||
UPDATE_INTERVAL = 60
|
UPDATE_INTERVAL = 60
|
||||||
|
|
||||||
logging.basicConfig(format=LOG_FORMAT, level=log_level, filename=LOG_FILE)
|
logging.basicConfig(format=LOG_FORMAT, level=log_level, filename=LOG_FILE)
|
||||||
#logging.basicConfig(format=LOG_FORMAT, level=log_level)
|
# logging.basicConfig(format=LOG_FORMAT, level=log_level)
|
||||||
log = logging.getLogger('bicycle-statistics')
|
log = logging.getLogger('bicycle-statistics')
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
|
@ -47,6 +47,46 @@ def plot_bar_chart(labels, ticklabels, values, title, xlabel, ylabel, filename,
|
|||||||
plt.savefig(filename)
|
plt.savefig(filename)
|
||||||
plt.close('all')
|
plt.close('all')
|
||||||
|
|
||||||
|
|
||||||
|
def plot_line_chart(values, ticklabels, title, xlabel, ylabel, filename, xtick_rotation=0):
|
||||||
|
'''Plot a line chart.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
values (dict): key: line name
|
||||||
|
value (list): line values
|
||||||
|
ticklabels (list): Names for the tick labels (must be same length as value list).
|
||||||
|
title (str): Title of the chart.
|
||||||
|
|
||||||
|
'''
|
||||||
|
fig = plt.figure()
|
||||||
|
ax1 = fig.add_subplot(111)
|
||||||
|
ax1.grid(zorder=0)
|
||||||
|
ax1.spines["top"].set_visible(False)
|
||||||
|
ax1.spines["bottom"].set_visible(False)
|
||||||
|
ax1.spines["left"].set_visible(False)
|
||||||
|
ax1.spines["right"].set_visible(False)
|
||||||
|
|
||||||
|
plt.title(title)
|
||||||
|
plt.xlabel(xlabel)
|
||||||
|
plt.ylabel(ylabel)
|
||||||
|
|
||||||
|
for key in values.keys():
|
||||||
|
if len(ticklabels) == len(values[key]):
|
||||||
|
plt.plot(ticklabels, values[key], label=key)
|
||||||
|
else:
|
||||||
|
short_ticklabels = list()
|
||||||
|
for i in range(0, len(values[key])):
|
||||||
|
short_ticklabels.append(ticklabels[i])
|
||||||
|
plt.plot(short_ticklabels, values[key], label=key)
|
||||||
|
|
||||||
|
x_base = numpy.arange(len(ticklabels))
|
||||||
|
plt.xticks(x_base, ticklabels, rotation=xtick_rotation)
|
||||||
|
|
||||||
|
plt.legend()
|
||||||
|
plt.savefig(filename)
|
||||||
|
plt.close('all')
|
||||||
|
|
||||||
|
|
||||||
class Gpx2Html(object):
|
class Gpx2Html(object):
|
||||||
def __init__(self, infolder, outfolder, logger):
|
def __init__(self, infolder, outfolder, logger):
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
@ -67,9 +107,12 @@ class Gpx2Html(object):
|
|||||||
self.logger.info("Begin update of png's/html...")
|
self.logger.info("Begin update of png's/html...")
|
||||||
distances = list()
|
distances = list()
|
||||||
avg_speeds = list()
|
avg_speeds = list()
|
||||||
|
distances_dict = dict()
|
||||||
for year in self.tracks.years():
|
for year in self.tracks.years():
|
||||||
distances.append(self.tracks.distances(year))
|
distances.append(self.tracks.distances(year))
|
||||||
|
distances_dict[year] = self.tracks.distances(year)
|
||||||
avg_speeds.append(self.tracks.avg_speeds(year))
|
avg_speeds.append(self.tracks.avg_speeds(year))
|
||||||
|
self.logger.info("{}: {}".format(year, self.tracks.distances))
|
||||||
|
|
||||||
plot_bar_chart(self.tracks.years(), MONTH_LABELS, distances,
|
plot_bar_chart(self.tracks.years(), MONTH_LABELS, distances,
|
||||||
'Distance', 'Month', 'km',
|
'Distance', 'Month', 'km',
|
||||||
@ -79,6 +122,26 @@ class Gpx2Html(object):
|
|||||||
'Average Speed', 'Month', 'km/h',
|
'Average Speed', 'Month', 'km/h',
|
||||||
os.path.join(self.outfolder, 'avg_spd.png'))
|
os.path.join(self.outfolder, 'avg_spd.png'))
|
||||||
|
|
||||||
|
# Accumulated distance:
|
||||||
|
accumulated_distances = dict()
|
||||||
|
for year in distances_dict.keys():
|
||||||
|
accumulated_distance = list()
|
||||||
|
accumulated_distance.append(0)
|
||||||
|
for i in range(0, len(distances_dict[year])):
|
||||||
|
accumulated_distance.append(accumulated_distance[i] + distances_dict[year][i])
|
||||||
|
accumulated_distances[year] = accumulated_distance
|
||||||
|
|
||||||
|
current_year = datetime.datetime.today().year
|
||||||
|
current_month = datetime.datetime.today().month
|
||||||
|
current_year_distance = list()
|
||||||
|
for i in range(0, current_month):
|
||||||
|
current_year_distance.append(accumulated_distances[current_year][i])
|
||||||
|
accumulated_distances[current_year] = current_year_distance
|
||||||
|
|
||||||
|
plot_line_chart(accumulated_distances, [""] + MONTH_LABELS,
|
||||||
|
"accumulated distance", 'Month', 'km',
|
||||||
|
os.path.join(self.outfolder, 'acc_dist.png'))
|
||||||
|
|
||||||
end_date = datetime.datetime.today()
|
end_date = datetime.datetime.today()
|
||||||
start_date = end_date - datetime.timedelta(days=14)
|
start_date = end_date - datetime.timedelta(days=14)
|
||||||
last_n_tracks = self.tracks.tracks(start_date, end_date)
|
last_n_tracks = self.tracks.tracks(start_date, end_date)
|
||||||
@ -182,6 +245,7 @@ class Gpx2Html(object):
|
|||||||
|
|
||||||
handle.write('<p>\n')
|
handle.write('<p>\n')
|
||||||
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('distance.png'))
|
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('distance.png'))
|
||||||
|
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('acc_dist.png'))
|
||||||
handle.write('<IMG SRC="{}" ALT="Distance">\n'.format('avg_spd.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('<IMG SRC="{}" ALT="Distance">\n'.format('last_14_days.png'))
|
||||||
handle.write('</p>\n')
|
handle.write('</p>\n')
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
from watchdog.events import PatternMatchingEventHandler
|
|
||||||
|
|
||||||
import threading
|
|
||||||
|
|
||||||
class InputObserver(PatternMatchingEventHandler):
|
|
||||||
def __init__(self, patterns=None, ignore_patterns=None,
|
|
||||||
ignore_directories=False, case_sensitive=False):
|
|
||||||
super(InputObserver, self).__init__(patterns, ignore_patterns,
|
|
||||||
ignore_directories, case_sensitive)
|
|
||||||
|
|
||||||
self.lock = threading.Lock()
|
|
||||||
self.lock.acquire()
|
|
||||||
self.new_filename = None
|
|
||||||
self.run_condition = True
|
|
||||||
|
|
||||||
|
|
||||||
# def on_created(self, event):
|
|
||||||
def on_any_event(self, event):
|
|
||||||
self.new_filename = event.src_path
|
|
||||||
self.lock.release()
|
|
||||||
|
|
||||||
|
|
||||||
def get_new_file(self):
|
|
||||||
self.lock.acquire() # don't release - will be released with next on_created
|
|
||||||
if self.run_condition == True:
|
|
||||||
return self.new_filename
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.run_condition = False
|
|
||||||
self.lock.release()
|
|
2
setup.py
2
setup.py
@ -10,7 +10,7 @@ NAME = 'bicycle-statistics'
|
|||||||
VERSION = '0.2.0'
|
VERSION = '0.2.0'
|
||||||
AUTHOR = 'Thomas Klaehn'
|
AUTHOR = 'Thomas Klaehn'
|
||||||
EMAIL = 'tkl@blackfinn.de'
|
EMAIL = 'tkl@blackfinn.de'
|
||||||
PACKAGES = ['bicycle_statistics', 'gpx_parser', 'gpx2html', 'input_observer']
|
PACKAGES = ['bicycle_statistics', 'gpx_parser', 'gpx2html']
|
||||||
SCRIPTS = ['example-gpx-parser', 'bicycle-stat']
|
SCRIPTS = ['example-gpx-parser', 'bicycle-stat']
|
||||||
|
|
||||||
DAEMON_START_SCRIPT = os.path.join("/lib/systemd/system", "bicycle-stat.service")
|
DAEMON_START_SCRIPT = os.path.join("/lib/systemd/system", "bicycle-stat.service")
|
||||||
|
Loading…
Reference in New Issue
Block a user