I have recently been working on a program which takes as input, log files generated from a running/biking app. These files are in an xml format which is incredibly regular. In my program, I first strip all of the geographic and time information, and output as a text file. Then, reading back this text file, instances of Entry class are compiled into a list. Using these entries, calculations (and eventually graphing and long term trends) can be achieved.
This python script requires the library geopy to use, and has been tested on Python3.
My main concern is how little of the code is pythonic in nature, with multiple if statements begging the question of optimization. I have uploaded a copy of an example input file for the script on my github, which can be found here. Typing '4-19-17a.bin' without the quotations at the prompt will begin parsing, and will print to standard output the string representation of each Entry instance that was created, along with a couple calculations.
dataparse.py
import xml.etree.ElementTree as ET
def processtimestring(time):
year = int(time[:4])
month = int(time[5:7])
day = int(time[8:10])
h = int(time[11:13])
m = int(time[14:16])
s = float(time[17:-6])
return [year, month, day, h, m, s]
def parsethedata():
time = []
lat = []
lng = []
alt = []
dist = []
garbage = '{http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2}'
filestring = input('The file to parse: ')
outputstring = filestring[:-4] + '.txt'
f = open(outputstring, 'w')
tree = ET.parse(filestring)
root = tree.getroot()
for child in root[0][0][1][4]:
for info in child:
if (not info.text):
for position in info:
f.write(position.tag.replace(garbage, '') + '\n')
f.write(position.text + '\n')
else:
f.write(info.tag.replace(garbage, '') + '\n')
f.write(info.text + '\n')
f.close()
with open(outputstring) as f:
for i, line in enumerate(f):
if ((i+9) % 10 == 0):
time.append(processtimestring(line[:-1]))
elif ((i+7) % 10 == 0):
lat.append(float(line[:-1]))
elif ((i+5) % 10 == 0):
lng.append(float(line[:-1]))
elif ((i+3) % 10 == 0):
alt.append(float(line[:-1]))
elif ((i+1) % 10 == 0):
dist.append(float(line[:-1]))
return [time, lat, lng, alt, dist]
entry.py
import geopy.distance
import datetime as dt
class Entry(object):
@staticmethod
def distancecalc(x1, x2):
coord_1 = (x1.pos[0], x1.pos[1])
coord_2 = (x2.pos[0], x2.pos[1])
return geopy.distance.vincenty(coord_1, coord_2).m
@staticmethod
def timecalc(x1, x2):
a, b = x1.time, x2.time
t1 = dt.datetime(a[0], a[1], a[2], a[3], a[4], int(a[5]))
t2 = dt.datetime(b[0], b[1], b[2], b[3], b[4], int(b[5]))
t1_decimal = float(a[5]-int(a[5]))
t2_decimal = float(b[5]-int(b[5]))
return (t2 - t1).total_seconds() + (t2_decimal - t1_decimal)
def __init__(self, time, lat, lng, alt, dist):
self.time = time
self.pos = [lat, lng]
self.alt = alt
self.dist = dist
def __str__(self):
ymd = ('ymd: ' + str(self.time[0]) + ', ' +
str(self.time[1]) + ', ' + str(self.time[2]))
hms = (' hms: ' + str(self.time[3]) + ', ' +
str(self.time[4]) + ', ' + str(self.time[5]))
lat = ' lat: ' + str(self.pos[0])
lng = ' lng: ' + str(self.pos[1])
alt = ' alt: ' + str(self.alt)
dst = ' dst: ' + str(self.dist)
stringrepresentation = ymd + hms + lat + lng + alt + dst
return stringrepresentation
main.py
import dataparse as dp
from entry import Entry
exitflag = False
while not exitflag:
[time, lat, lng, alt, dist] = dp.parsethedata()
entries = [Entry(x, lat[i], lng[i],
alt[i], dist[i]) for i, x in enumerate(time)]
prev = entries[0]
total = 0.0
for entry in entries:
dx = Entry.distancecalc(prev, entry)
dt = Entry.timecalc(prev, entry)
total += dx
print('Total: ' + str(total) + ', Logged Dist: ' + str(entry.dist) +
', dx: ' + str(dx) + ', dt: ' + str(dt), end="")
if dt:
print(', Speed: ' + str(dx/dt))
else:
print(', Speed: 0.0')
prev = entry
userinput = input('Parse another file? y/n: ')
if userinput == 'n':
exitflag = True