Happy 2017

We have some GPX files which we want to plot on a nice map. A lot of the the code below is based on this python4oceanographers blog post.

First we import some packages necessary to achieve what we want.

In [1]:
import matplotlib.pyplot as plt
%matplotlib inline
import numpy
import gpxpy
import mplleaflet
import glob
import os
import pandas

plt.rcParams['figure.figsize'] = (16, 9)  # Size up figures a bit

To quickly ingest the GPX files, we write (or actually copy from the aforementioned blog post) a parsing function.

In [2]:
def load_run_data(gpx_path, filter=""):
    gpx_files = glob.glob(os.path.join(gpx_path, filter + "*.gpx"))
    run_data = []
    for file_idx, gpx_file in enumerate(gpx_files): 
        gpx = gpxpy.parse(open(gpx_file, 'r'))
        # Loop through tracks
        for track_idx, track in enumerate(gpx.tracks):
            track_name = track.name
            track_time = track.get_time_bounds().start_time
            track_length = track.length_3d()
            track_duration = track.get_duration()
            track_speed = track.get_moving_data().max_speed
            
            for seg_idx, segment in enumerate(track.segments):
                segment_length = segment.length_3d()
                for point_idx, point in enumerate(segment.points):
                    run_data.append([file_idx, os.path.basename(gpx_file), track_idx, track_name, 
                                     track_time, track_length, track_duration, track_speed, 
                                     seg_idx, segment_length, point.time, point.latitude, 
                                     point.longitude, point.elevation, segment.get_speed(point_idx)])
    return run_data

For easy handling, we load the GPX tracks in their subfolder to a Pandas dataframe and display the first few entries of the data frame.

In [3]:
data = load_run_data(gpx_path='gpxtracks', filter="")
df = pandas.DataFrame(data, columns=['File_Index', 'File_Name', 'Index', 'Name',
                                     'Time', 'Length', 'Duration', 'Max_Speed',
                                     'Segment_Index', 'Segment_Length', 'Point_Time', 'Point_Latitude',
                                     'Point_Longitude', 'Point_Elevation', 'Point_Speed'])
df.head()
Out[3]:
File_Index File_Name Index Name Time Length Duration Max_Speed Segment_Index Segment_Length Point_Time Point_Latitude Point_Longitude Point_Elevation Point_Speed
0 0 0.gpx 0 2016-12-09 13:57:01 2016-12-09 12:57:01 2865.836836 483 9.251168 0 2865.836836 2016-12-09 12:57:01 46.945007 7.429614 536.564941 NaN
1 0 0.gpx 0 2016-12-09 13:57:01 2016-12-09 12:57:01 2865.836836 483 9.251168 0 2865.836836 2016-12-09 12:57:02 46.945055 7.429586 540.644531 9.099847
2 0 0.gpx 0 2016-12-09 13:57:01 2016-12-09 12:57:01 2865.836836 483 9.251168 0 2865.836836 2016-12-09 12:57:03 46.945151 7.429544 541.273682 10.243475
3 0 0.gpx 0 2016-12-09 13:57:01 2016-12-09 12:57:01 2865.836836 483 9.251168 0 2865.836836 2016-12-09 12:57:04 46.945223 7.429530 536.550049 8.525432
4 0 0.gpx 0 2016-12-09 13:57:01 2016-12-09 12:57:01 2865.836836 483 9.251168 0 2865.836836 2016-12-09 12:57:05 46.945287 7.429538 539.381104 6.911977

At last we plot the tracks on top of the awesome Stamen watercolor maps.

In [4]:
for i in range(max(df['File_Index'])+1):
    plt.plot(df['Point_Longitude'][df['File_Index']==i],
             df['Point_Latitude'][df['File_Index']==i],
             color='black', linewidth=7)
mplleaflet.display(tiles='stamen_wc')
Out[4]:
In [5]:
# Save as HTML page, so we can print the image big...
for i in range(max(df['File_Index'])+1):
    plt.plot(df['Point_Longitude'][df['File_Index']==i],
             df['Point_Latitude'][df['File_Index']==i],
             color='black', linewidth=7)
mplleaflet.save_html(tiles='stamen_wc', fileobj='2017.html')