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)


50

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'


19  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

Plotting a single run


In [8]:
run_map, run_bounds = plot_run(runs[4])
run_map.fit_bounds(run_bounds)
run_map


Out[8]:

Plotting all runs


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 [ ]: