Creating GPX File Viewer in Python

GPX file is a GPS data that stored in XML format. There are some types of data that stored in GPS namely waypoint, route and track. Track is a type of data which is recorded regularly by  GPS in an interval. Therefore, with GPS tracker data we can visualize a trip that we did, which road we passed by, the length of track, time taken, etc. There are some tools or apps that available to view or visualize a GPS track file such as ArcGIS, QGIS, Google Earth and also some online GPX viewer app also available to visualize a GPS tracker data. Just do online searching and you will find many of them.

In this tutorial, I will discuss how to create a GPX track file viewer in Python. I'm using Jupyter Notebook with Python 3. So if you want to run the code make sure you have Jupyter Notebook installed in your machine. We will visualize the track itself, speed and elevation profile along the track. Moreover the visualization will be dynamic in an animation that plot each GPS tracking point as in the figure below.
To create the GPX file viewer we need some modules like matplotlib, time, IPython, xml dom and math. Import all the required modules as in the code below.

import matplotlib.pyplot as plt
import time
from IPython import display
from xml.dom import minidom
import math  

Then open a GPX file and parse the data using minidom. Here we are taking some important elements: 'trkpt', 'ele' and 'time' for track point, elevation and time.

#READ GPX FILE
data=open('F:/ride.gpx')
xmldoc = minidom.parse(data)
track = xmldoc.getElementsByTagName('trkpt')
elevation=xmldoc.getElementsByTagName('ele')
datetime=xmldoc.getElementsByTagName('time')
n_track=len(track)

After getting those elements, we need to get the value from each elements. Then we need to parse the elements to get latitude, longitude, elevation and time. At the end, the time is converted to second. It will be used later in speed calculation.

#PARSING GPX ELEMENT
lon_list=[]
lat_list=[]
h_list=[]
time_list=[]
for s in range(n_track):
    lon,lat=track[s].attributes['lon'].value,track[s].attributes['lat'].value
    elev=elevation[s].firstChild.nodeValue
    lon_list.append(float(lon))
    lat_list.append(float(lat))
    h_list.append(float(elev))
    # PARSING TIME ELEMENT
    dt=datetime[s].firstChild.nodeValue
    time_split=dt.split('T')
    hms_split=time_split[1].split(':')
    time_hour=int(hms_split[0])
    time_minute=int(hms_split[1])
    time_second=int(hms_split[2].split('Z')[0])
    total_second=time_hour*3600+time_minute*60+time_second
    time_list.append(total_second)

Now we have all parameters that are needed to create the GPX file viewer. To do further calculation like distance and speed, we create some functions namely geo2cart, distance and speed. geo2cart is a function to convert Geodetic coordinate into Cartesian coordinate with WGS-84 ellipsoid reference datum. We need the Cartesian coordinate because it will be used to calculate a distance in meter between two GPS tracking points. After getting the distance, then the speed in m/s can be calculated by divided with time difference.
 
#GEODETIC TO CARTERSIAN FUNCTION
def geo2cart(lon,lat,h):
    a=6378137 #WGS 84 Major axis
    b=6356752.3142 #WGS 84 Minor axis
    e2=1-(b**2/a**2)
    N=float(a/math.sqrt(1-e2*(math.sin(math.radians(abs(lat)))**2)))
    X=(N+h)*math.cos(math.radians(lat))*math.cos(math.radians(lon))
    Y=(N+h)*math.cos(math.radians(lat))*math.sin(math.radians(lon))
    return X,Y

#DISTANCE FUNCTION
def distance(x1,y1,x2,y2):
    d=math.sqrt((x1-x2)**2+(y1-y2)**2)
    return d

#SPEED FUNCTION
def speed(x0,y0,x1,y1,t0,t1):
    d=math.sqrt((x0-x1)**2+(y0-y1)**2)
    delta_t=t1-t0
    s=float(d/delta_t)
    return s

Next step, using the function we do calculation of distance and speed. The result are stored in distance and speed list.

#POPULATE DISTANCE AND SPEED LIST
d_list=[0.0]
speed_list=[0.0]
l=0
for k in range(n_track-1):
    if k<(n_track-1):
        l=k+1
    else:
        l=k
    XY0=geo2cart(lon_list[k],lat_list[k],h_list[k])
    XY1=geo2cart(lon_list[l],lat_list[l],h_list[l])
    
    #DISTANCE
    d=distance(XY0[0],XY0[1],XY1[0],XY1[1])
    sum_d=d+d_list[-1]
    d_list.append(sum_d)
    
    #SPEED
    s=speed(XY0[0],XY0[1],XY1[0],XY1[1],time_list[k],time_list[l])
    speed_list.append(s)

Now we can visualize the GPX file track data with three plots: Track, speed and elevation profile.

#PLOT TRACK
f,(track,speed,elevation)=plt.subplots(3,1)
f.set_figheight(8)
f.set_figwidth(5)
plt.subplots_adjust(hspace=0.5)
track.plot(lon_list,lat_list,'k')
track.set_ylabel("Latitude")
track.set_xlabel("Longitude")
track.set_title("Track Plot")

#PLOT SPEED
speed.bar(d_list,speed_list,30,color='w',edgecolor='w')
speed.set_title("Speed")
speed.set_xlabel("Distance(m)")
speed.set_ylabel("Speed(m/s)")

#PLOT ELEVATION PROFILE
base_reg=0
elevation.plot(d_list,h_list)
elevation.fill_between(d_list,h_list,base_reg,alpha=0.1)
elevation.set_title("Elevation Profile")
elevation.set_xlabel("Distance(m)")
elevation.set_ylabel("GPS Elevation(m)")
elevation.grid()

Lastly in a loop, dynamic plot is created in one second interval by plotting each tracking points over the track and elevation profile. The speed change is visualized in a bar chart.
 
#ANIMATION/DYNAMIC PLOT
for i in range(n_track):
    track.plot(lon_list[i],lat_list[i],'yo')
    speed.bar(d_list[i],speed_list[i],30,color='g',edgecolor='g')
    elevation.plot(d_list[i],h_list[i],'ro')
    display.display(plt.gcf())
    display.clear_output(wait=True)
    time.sleep(1)
    
plt.show()
That's all the tutorial how to create a GPX file viewer to visualize track, speed and elevation profile with Python in Jupyter Notebook. You can try to run the code by downloading the GPX file viewer Jupyter Notebook and a GPX file sample that used in this tutorial. Finally use your own GPX track file and try to visualize it with the code.
 

Related Posts

Disqus Comments