#! /usr/bin/env python # Copyright (C) 2009 by Akkana Peck. # You are free to use, share or modify this program under # the terms of the GPLv2 or, at your option, any later GPL. import sys, os, math, xml.dom.minidom import pylab #import matplotlib.pyplot as plt #from matplotlib.dates import YearLocator, MonthLocator, DateFormatter #import datetime # Climb threshold: any short climb that doesn't gain more than # this number of feet won't be counted toward total climb. # GPS units (at least my Vista CX) have a lot of 1-2' # fluctuations that vastly overestimate the climb total; # just swinging the bag around, or unhooking it from your belt # to check your current position, can do that. CLIMB_THRESHOLD = 8 # The variables we're going to plot: times = [ ] eles = [ ] distances = [ ] # Some evil globals because python doesn't have static variables: lastlat = 0 lastlon = 0 lastele = -1 dist = 0 total_climb = 0 this_climb = 0 this_climb_start = 0 def getVal(parent, name): nodeList = parent.getElementsByTagName(name) if len(nodeList) < 1 : return "No " + name + " element" children = nodeList[0].childNodes if len(children) < 1 : return "No " + name + " children" node = children[0] if node.nodeType != node.TEXT_NODE: return name + " isn't a text node" return node.data def accumulate_climb(ele) : global lastele, total_climb, this_climb, this_climb_start if lastele >= 0 : # Not the first call if ele > lastele : # Climbed since last step if this_climb == 0 : this_climb_start = lastele this_climb = this_climb + ele - lastele else : if this_climb > CLIMB_THRESHOLD : total_climb = total_climb + this_climb this_climb = 0 elif ele <= this_climb_start : # We got a little hump but it isn't big enough to count; # probably an artifact like taking the GPS out of its case # or getting off the bike or something. So reset. this_climb = 0 lastele = ele def handleTrackPoint(point) : global lastlat, lastlon, dist time = getVal(point, "time") lat = float(point.getAttribute("lat")) lon = float(point.getAttribute("lon")) ele = float(getVal(point, "ele")) ele = round(ele * 3.2808399, 2) # convert from meters to feet if lastlat != 0 and lastlon != 0 : dist = dist + math.sqrt((lat - lastlat)**2 + (lon - lastlon)**2) * 69.046767 # 69.046767 converts nautical miles (arcminutes) to miles accumulate_climb(ele) lastlat = lat lastlon = lon #print dist, ele, "\t", time, lat, lon, "\t", total_climb #print dist, ele, "\t", time, total_climb distances.append(dist) eles.append(ele) def handleTrackFile(dom) : points = dom.getElementsByTagName("trkpt") for i in range (0, len(points), 1) : handleTrackPoint(points[i]) accumulate_climb(0) def main(args) : if len(args) < 2 : print "Usage:", args[0], file.gpx return 1 # # Parse the file: # try : dom = xml.dom.minidom.parse(args[1]) except IOError, e: print e #print dir(e) return e.errno handleTrackFile(dom) # # Plot the results: # pylab.plot(distances, eles) title_string = "Elevation profile (" + str(round(distances[-1], 1)) \ + " miles, " + str(int(total_climb)) + "' total climb)" pylab.title(title_string) pylab.xlabel("miles") # pylab.get_current_fig_manager().window.set_title(os.path.basename(args[0] + ": " + title_string)) pylab.ylabel("feet") pylab.grid(True) pylab.show() pass return 0 if __name__ == "__main__" : try: sys.exit(main(sys.argv)) except KeyboardInterrupt: print " Bye!" sys.exit(1)