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.
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.
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.
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()
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.
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')
# 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')