Example of using the awesome folium lib to plot run paths on map.
In [1]:
import os
import pylab as pl
import numpy as np
import pandas as pd
import calendar
import folium
import sportdata.io.tcx as tcx
%matplotlib inline
In [2]:
# Directory where to find .tcx files
DATA_DIR = '../../garmin_data'
tcx_files = [os.path.join(DATA_DIR, fname) for fname in os.listdir(DATA_DIR) if fname.endswith('.tcx')]
print len(tcx_files)
In [3]:
activities = [tcx.load_activity(fname) for fname in tcx_files]
In [4]:
# Filter only 'Running' activities
runs = [act for act in activities if act.sport == 'Running']
print np.count_nonzero(runs), ' running activities'
In [5]:
def time_to_timestamp_ms(time):
return calendar.timegm(time.timetuple()) * 1000
def run_to_numpy(act):
"""
Extract latlng points from a run
Returns:
time: The timestamps (in milliseconds) of each point
pos: The (lat, lng) pos of each point as a Nx2 array
"""
trackpoints = [lap.trackpoints for lap in act.laps]
trackpoints = reduce(lambda x, y: x + y, trackpoints)
times = np.array([time_to_timestamp_ms(pt.time) for pt in trackpoints])
# Some trackpoints might have a missing latlng (if the position is unknown due to e.g. clouds)
pos = np.array([pt.latlng for pt in trackpoints if pt.latlng is not None])
return times, pos
In [6]:
def compute_bounds(latlng_pts):
"""Returns bbox southwest, northeast"""
southwest = np.min(latlng_pts, axis=0)
northeast = np.max(latlng_pts, axis=0)
return tuple(southwest), tuple(northeast)
In [7]:
def plot_run(activity, folium_map=None):
run_time, run_pos = run_to_numpy(activity)
if folium_map is None:
folium_map = folium.Map(location=tuple(np.mean(run_pos, axis=0)))
folium_map.add_children(folium.PolyLine(
[tuple(p) for p in run_pos], color='red', opacity=1.0
))
bounds = compute_bounds(run_pos)
return folium_map, bounds
In [8]:
run_map, run_bounds = plot_run(runs[4])
run_map.fit_bounds(run_bounds)
run_map
Out[8]:
In [9]:
run_map = None
bounds = (np.inf, np.inf), (-np.inf, -np.inf)
for run in runs:
run_map, run_bounds = plot_run(run, run_map)
bounds = tuple(np.min(np.c_[bounds[0], run_bounds[0]], axis=1)),\
tuple(np.max(np.c_[bounds[1], run_bounds[1]], axis=1))
run_map.fit_bounds(bounds)
# You could save the map to an HTML file
#run_map.save('my_map.html')
run_map
Out[9]:
In [ ]: