In [1]:
import os
import folium

print(folium.__version__)


0.8.3+52.g2758dc7.dirty

In [2]:
import gpxpy
import requests


url = 'https://raw.githubusercontent.com/python-visualization/folium/master/examples/data'
fname = f'{url}/2014_08_05_farol.gpx'
gpx = gpxpy.parse(requests.get(fname).text)

print('{} track(s)'.format(len(gpx.tracks)))
track = gpx.tracks[0]

print('{} segment(s)'.format(len(track.segments)))
segment = track.segments[0]

print('{} point(s)'.format(len(segment.points)))


1 track(s)
1 segment(s)
1027 point(s)

In [3]:
data = []
segment_length = segment.length_3d()
for point_idx, point in enumerate(segment.points):
    data.append(
        [
            point.longitude,
            point.latitude,
            point.elevation,
            point.time,
            segment.get_speed(point_idx)
        ]
    )

In [4]:
from pandas import DataFrame

columns = ['Longitude', 'Latitude', 'Altitude', 'Time', 'Speed']
df = DataFrame(data, columns=columns)
df.head()


Out[4]:
Longitude Latitude Altitude Time Speed
0 -38.502595 -13.005390 10.9 2014-08-05 17:52:49.330000+00:00 NaN
1 -38.502605 -13.005415 11.8 2014-08-05 17:52:49.770000+00:00 2.677749
2 -38.502575 -13.005507 11.7 2014-08-05 17:52:54.730000+00:00 3.065225
3 -38.502545 -13.005595 11.6 2014-08-05 17:52:57.750000+00:00 4.228354
4 -38.502515 -13.005680 11.4 2014-08-05 17:53:00.720000+00:00 3.947037

In [5]:
import numpy as np
from geographiclib.geodesic import Geodesic

angles = [90]
for i in range(len(df) - 1):
    info = Geodesic.WGS84.Inverse(
        df.iloc[i, 1], df.iloc[i, 0],
        df.iloc[i + 1, 1], df.iloc[i + 1, 0]
    )
    angles.append(info['azi2'])

# Change from CW-from-North to CCW-from-East.
angles = np.deg2rad(450 - np.array(angles))

# Normalize the speed to use as the length of the arrows.
r = df['Speed'] / df['Speed'].max()
df['u'] = r * np.cos(angles)
df['v'] = r * np.sin(angles)

In [6]:
import mplleaflet
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
df = df.dropna()

# This style was lost below.
ax.plot(
    df['Longitude'],
    df['Latitude'],
    color='darkorange',
    linewidth=5,
    alpha=0.5
)

# This is preserved in the SVG icon.
sub = 10
kw = {'color': 'deepskyblue', 'alpha': 0.8, 'scale': 10}
ax.quiver(df['Longitude'][::sub],
          df['Latitude'][::sub],
          df['u'][::sub],
          df['v'][::sub], **kw)

gj = mplleaflet.fig_to_geojson(fig=fig)

In [7]:
import folium

lon, lat = -38.51386097, -13.00868051
zoom_start = 14

m = folium.Map(
    location=[lat, lon],
    tiles='Cartodb Positron',
    zoom_start=zoom_start
)

# The first geometry is a lineString.
line_string = gj['features'][0]
gjson = folium.features.GeoJson(line_string)

m.add_child(gjson)
m.save(os.path.join('results', 'Folium_and_mplleaflet_0.html'))

m


Out[7]:

In [8]:
line_string['properties']


Out[8]:
{'color': '#FF8C00', 'weight': 5.0, 'opacity': 0.5}

In [9]:
from IPython.display import HTML

msg = '<font color="{}">This should be darkorange!</font>'.format
HTML(msg(line_string['properties']['color']))


Out[9]:
This should be darkorange!

In [10]:
m = folium.Map(
    location=[lat, lon],
    tiles='Cartodb Positron',
    zoom_start=zoom_start
)

icon_size = (14, 14)

for feature in gj['features']:
    if feature['geometry']['type'] == 'LineString':
        continue
    elif feature['geometry']['type'] == 'Point':
        lon, lat = feature['geometry']['coordinates']
        html = feature['properties']['html']

        icon_anchor = (feature['properties']['anchor_x'],
                       feature['properties']['anchor_y'])

        icon = folium.features.DivIcon(html=html,
                                       icon_size=(14, 14),
                                       icon_anchor=icon_anchor)
        marker = folium.map.Marker([lat, lon], icon=icon)
        m.add_child(marker)
    else:
        msg = 'Unexpected geometry {}'.format
        raise ValueError(msg(feature['geometry']))

m.save(os.path.join('results', 'Folium_and_mplleaflet_1.html'))

m


Out[10]: