Since OpenPaths is dead, we switched to WHIB, which wasn't owned by Facebook (or actually also dead now) and doesn't drain the battery of my phone quickly. A 2$ premium feature lets you export all the data as CSV, which is easy to parse and display.

In [1]:
import glob
import pandas
import geopy
import geopy.distance
import geopy.geocoders
import folium
import folium.plugins
In [2]:
# Which year do we want to look at?
whichyear = 2020
In [3]:
# Tile providers
# Available tiles: https://github.com/python-visualization/folium/blob/master/folium/folium.py#L75
#tileprovider = 'Mapbox Bright'
tileprovider = 'Cartodb positron'
#tileprovider = 'Cartodb dark_matter'
#tileprovider = 'Mapbox Control Room'
#tileprovider = 'Stamen Toner'
In [4]:
# Default zoom level and circle marker radius for map
zoom_start = 7
radius = 10
In [5]:
# Settings for address lookup
geopy.geocoders.options.default_user_agent = 'Jahresrückblick Habi'
geolocator = geopy.geocoders.Nominatim()
In [6]:
# Read in locations from newest CSV-file in the current directory
locations = pandas.read_csv(sorted(glob.glob('journey*.csv'))[-1])
In [7]:
# Modify the dataframe
locations.drop(['Crumb'], axis=1, inplace=True)
locations.rename(columns={'LocalDate': 'Date'}, inplace=True)
locations.rename(columns={'LocalTime': 'Time'}, inplace=True)
locations.rename(columns={'Altitude (in metres)': 'Altitude'}, inplace=True)
locations.rename(columns={'Accuracy (in metres)': 'Accuray'}, inplace=True)
In [8]:
# Make us a proper date column, based on https://stackoverflow.com/a/26763793
locations['Date'] = pandas.to_datetime(locations['Date'])
# Make us a year, month and weekday colum, based on https://stackoverflow.com/q/48623332
locations['Year'] = locations.Date.dt.year
locations['Month'] = locations.Date.dt.month
locations['Day'] = locations.Date.dt.day
locations['Weekday'] = locations.Date.dt.dayofweek
In [9]:
len(locations)
Out[9]:
44918
In [10]:
# Drop all values not in 'whichyear'
# https://stackoverflow.com/a/27360130
locations.drop(locations[locations.Year != whichyear].index, inplace=True)
# Reset index, so that we can find the correct date lateron
locations.reset_index(drop=True, inplace=True)
In [11]:
len(locations)
Out[11]:
13199
In [12]:
# Drop all values not in a certain month
# locations.drop(locations[locations.Month != 7].index, inplace=True)
In [13]:
locations.head()
Out[13]:
Date Time Latitude Longitude Altitude Accuray Year Month Day Weekday
0 2020-01-01 15:27 46.935439 7.417876 554 22 2020 1 1 2
1 2020-01-01 15:29 46.937750 7.420747 554 113 2020 1 1 2
2 2020-01-01 15:30 46.937342 7.420489 553 65 2020 1 1 2
3 2020-01-01 15:30 46.937823 7.420831 553 165 2020 1 1 2
4 2020-01-01 15:30 46.937320 7.420576 554 65 2020 1 1 2
In [14]:
locations.tail()
Out[14]:
Date Time Latitude Longitude Altitude Accuray Year Month Day Weekday
13194 2020-12-30 21:10 46.933922 7.420873 555 65 2020 12 30 2
13195 2020-12-30 21:14 46.934375 7.423488 563 5 2020 12 30 2
13196 2020-12-30 21:23 46.935573 7.418067 0 0 2020 12 30 2
13197 2020-12-30 21:24 46.934937 7.419521 0 5 2020 12 30 2
13198 2020-12-31 08:29 46.935416 7.417994 551 65 2020 12 31 3
In [15]:
locations.describe()
Out[15]:
Latitude Longitude Altitude Accuray Year Month Day Weekday
count 13199.000000 13199.000000 13199.000000 13199.000000 13199.0 13199.000000 13199.000000 13199.000000
mean 46.894718 7.503041 622.190772 163.953254 2020.0 6.066672 15.642018 3.146223
std 0.195932 0.535544 448.495020 681.104242 0.0 3.408552 8.666418 1.927811
min 46.294022 5.646590 -1.000000 0.000000 2020.0 1.000000 1.000000 0.000000
25% 46.930135 7.417976 535.000000 30.000000 2020.0 3.000000 8.000000 2.000000
50% 46.938278 7.426609 550.000000 65.000000 2020.0 6.000000 16.000000 3.000000
75% 46.948771 7.442524 562.000000 76.000000 2020.0 9.000000 23.000000 5.000000
max 47.712867 10.036439 2613.000000 20000.000000 2020.0 12.000000 31.000000 6.000000
In [16]:
# Show the extreme locations on a map
# Marker colors from here: https://stackoverflow.com/a/41993318
m = folium.Map(location=[locations['Latitude'].mean(),
                         locations['Longitude'].mean()],
               tiles=tileprovider,
               zoom_start=zoom_start)
# Altitude
for c, loc in locations.sort_values(by=['Altitude'],
                                    ascending=False).head(1).iterrows():
    folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                        radius=radius,
                        popup='Highest: %s' % (loc.Date),
                       ).add_to(m)
# North
for c, loc in locations.sort_values(by=['Latitude'],
                                    ascending=False).head(1).iterrows():
    folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                        radius=radius,
                        popup='North: %s' % (loc.Date),
                       ).add_to(m)
# East
for c, loc in locations.sort_values(by=['Longitude'],
                                    ascending=False).head(1).iterrows():
    folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                        radius=radius,
                        popup='East: %s' % (loc.Date),
                       ).add_to(m)
# South
for c, loc in locations.sort_values(by=['Latitude']).head(1).iterrows():
    folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                        radius=radius,
                        popup='South: %s' % (loc.Date),
                       ).add_to(m)
# West
for c, loc in locations.sort_values(by=['Longitude']).head(1).iterrows():
    folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                        radius=radius,
                        popup='West: %s' % (loc.Date),
                       ).add_to(m)
m
Out[16]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [17]:
# Show north, east, south, west extreme (with averaged lat/lon for each)
m = folium.Map(location=[locations['Latitude'].mean(),
                         locations['Longitude'].mean()],
                tiles=tileprovider,
                zoom_start=zoom_start)
folium.CircleMarker(location=[locations.Latitude.mean(),
                              locations.Longitude.min()],
                    radius=radius,
                    popup='Average West').add_to(m)
folium.CircleMarker(location=[locations.Latitude.mean(),
                              locations.Longitude.max()],
                    radius=radius,
                    popup='Average East').add_to(m)
folium.CircleMarker(location=[locations.Latitude.max(),
                              locations.Longitude.mean()],
                    radius=radius,
                    popup='Average North').add_to(m)
folium.CircleMarker(location=[locations.Latitude.min(),
                              locations.Longitude.mean()],
                    radius=radius,
                    popup='Average South').add_to(m)
m
Out[17]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [18]:
# How far did we come?
print('In %s, we traveled %0.0f km north-south' % (whichyear,
                                                   geopy.distance.geodesic([locations.Latitude.min(),
                                                                            locations.Longitude.mean()],
                                                                         [locations.Latitude.max(),
                                                                          locations.Longitude.mean()]).km))
print('In %s, we traveled %0.0f km east-west' % (whichyear,
                                                 geopy.distance.geodesic([locations.Latitude.mean(),
                                                                          locations.Longitude.min()],
                                                                         [locations.Latitude.mean(),
                                                                          locations.Longitude.max()]).km))
In 2020, we traveled 158 km north-south
In 2020, we traveled 334 km east-west

By using the geocoding library for Python and the OpenStreetMap reverse geocoding tool we can assign addresses to locations.

In [19]:
# Get all extrema locations
location_average = [locations['Latitude'].mean(), locations['Longitude'].mean()]
location_median = [locations['Latitude'].median(), locations['Longitude'].median()]
location_north = [locations[locations.Latitude == locations.Latitude.max()].Latitude.values[0],
                  locations[locations.Latitude == locations.Latitude.max()].Longitude.values[0]]
location_east = [locations[locations.Longitude == locations.Longitude.max()].Latitude.values[0],
                 locations[locations.Longitude == locations.Longitude.max()].Longitude.values[0]]
location_south = [locations[locations.Latitude == locations.Latitude.min()].Latitude.values[0],
                  locations[locations.Latitude == locations.Latitude.min()].Longitude.values[0]]
location_west = [locations[locations.Longitude == locations.Longitude.min()].Latitude.values[0],
                 locations[locations.Longitude == locations.Longitude.min()].Longitude.values[0]]
location_top = [locations[locations['Altitude'] == locations['Altitude'].max()].Latitude.values[0],
                locations[locations['Altitude'] == locations['Altitude'].max()].Longitude.values[0]]
In [20]:
# Turn debug on to print and thus find the right value of the address
debug = True
In [21]:
# According to https://github.com/openstreetmap/Nominatim/issues/885#issuecomment-358123829
# we have to
# > Look for the first of 'city', 'town', 'village', 'hamlet', 'suburb'
# Let's do this!
potentialplacename = ['city', 'town', 'village', 'hamlet', 'suburb']
In [22]:
# Address lookup with `geopy` and https://wiki.openstreetmap.org/wiki/Nominatim
location_average_geo = geolocator.reverse(location_average)
# Print the details, so we can get the correct value to save below
if debug:
    print(location_average_geo.raw)
# Save us a name and print it
for p in potentialplacename:
    if location_average_geo.raw.get('address').get(p):
        name_average = location_average_geo.raw.get('address').get(p)
print('The average location in %s was in %s' % (whichyear, name_average))
# Show the point on a map
m = folium.Map(location=[float(location_average_geo.raw.get('lat')),
                         float(location_average_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_average_geo.raw.get('lat')),
                              float(location_average_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_average).add_to(m)
m
{'place_id': 96561807, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 25742009, 'lat': '46.89573273245403', 'lon': '7.503418321899902', 'display_name': 'Chummewägli, Belp, Verwaltungskreis Bern-Mittelland, Verwaltungsregion Bern-Mittelland, Bern/Berne, 3123, Schweiz/Suisse/Svizzera/Svizra', 'address': {'road': 'Chummewägli', 'city_district': 'Belp', 'town': 'Belp', 'county': 'Verwaltungskreis Bern-Mittelland', 'state_district': 'Verwaltungsregion Bern-Mittelland', 'state': 'Bern/Berne', 'postcode': '3123', 'country': 'Schweiz/Suisse/Svizzera/Svizra', 'country_code': 'ch'}, 'boundingbox': ['46.8952922', '46.8966828', '7.5005797', '7.5047264']}
The average location in 2020 was in Belp
Out[22]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [23]:
location_median_geo = geolocator.reverse(location_median)
if debug:
    print(location_median_geo.raw)
for p in potentialplacename:
    if location_median_geo.raw.get('address').get(p):
        name_median = location_median_geo.raw.get('address').get(p)
print('The median location in %s was in %s' % (whichyear, name_median))
m = folium.Map(location=[float(location_median_geo.raw.get('lat')),
                         float(location_median_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_median_geo.raw.get('lat')),
                              float(location_median_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_median).add_to(m)
m
{'place_id': 103550584, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 54032876, 'lat': '46.938094199999995', 'lon': '7.42629543528194', 'display_name': 'Weissenheim, Weissensteinstrasse, Mattenhof, Stadtteil III, Bern, Verwaltungskreis Bern-Mittelland, Verwaltungsregion Bern-Mittelland, Bern/Berne, 3007, Schweiz/Suisse/Svizzera/Svizra', 'address': {'amenity': 'Weissenheim', 'road': 'Weissensteinstrasse', 'quarter': 'Mattenhof', 'city_district': 'Stadtteil III', 'city': 'Bern', 'county': 'Verwaltungskreis Bern-Mittelland', 'state_district': 'Verwaltungsregion Bern-Mittelland', 'state': 'Bern/Berne', 'postcode': '3007', 'country': 'Schweiz/Suisse/Svizzera/Svizra', 'country_code': 'ch'}, 'boundingbox': ['46.937432', '46.9387388', '7.4253894', '7.4268348']}
The median location in 2020 was in Bern
Out[23]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [24]:
## Get day of location, based on 
# https://stackoverflow.com/a/53979441/323100
# and 
# https://strftime.org
# print(locations[locations.eq(location_north[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d'))
In [25]:
location_north_geo = geolocator.reverse(location_north)
if debug:
    print(location_north_geo.raw)
for p in potentialplacename:
    if location_north_geo.raw.get('address').get(p):
        name_north = location_north_geo.raw.get('address').get(p)
print('The northmost location in %s was in '
      '%s, %s on %s' % (whichyear,
                        name_north,
                        location_north_geo.raw.get('address').get('country'),
                        locations[locations.eq(location_north[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d')))
m = folium.Map(location=[float(location_north_geo.raw.get('lat')),
                         float(location_north_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_north_geo.raw.get('lat')),
                              float(location_north_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_north).add_to(m)
m
{'place_id': 97076814, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 26473431, 'lat': '47.71210485', 'lon': '9.595824440879598', 'display_name': 'Ravensburger Spieleland, 1, Am Hangenwald, Liebenau, Meckenbeuren, Bodenseekreis, Baden-Württemberg, 88074, Deutschland', 'address': {'tourism': 'Ravensburger Spieleland', 'house_number': '1', 'road': 'Am Hangenwald', 'village': 'Liebenau', 'town': 'Meckenbeuren', 'county': 'Bodenseekreis', 'state': 'Baden-Württemberg', 'postcode': '88074', 'country': 'Deutschland', 'country_code': 'de'}, 'boundingbox': ['47.7099864', '47.7141751', '9.592214', '9.5994468']}
The northmost location in 2020 was in Liebenau, Deutschland on August, 10
Out[25]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [26]:
location_east_geo = geolocator.reverse(location_east)
if debug:
    print(location_east_geo.raw)
for p in potentialplacename:
    if location_east_geo.raw.get('address').get(p):
        name_east = location_east_geo.raw.get('address').get(p)
print('The most eastern location in %s was in '
      '%s, %s on %s' % (whichyear,
                        name_east,
                        location_east_geo.raw.get('address').get('country'),
                        locations[locations.eq(location_east[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d')))
m = folium.Map(location=[float(location_east_geo.raw.get('lat')),
                         float(location_east_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_east_geo.raw.get('lat')),
                              float(location_east_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_east).add_to(m)
m
{'place_id': 101917843, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 40219491, 'lat': '47.3030893898817', 'lon': '10.036705071024098', 'display_name': 'Bregenzerwaldstraße, Gemeinde Schoppernau, Bezirk Bregenz, Vorarlberg, 6886, Österreich', 'address': {'road': 'Bregenzerwaldstraße', 'city': 'Gemeinde Schoppernau', 'county': 'Bezirk Bregenz', 'state': 'Vorarlberg', 'postcode': '6886', 'country': 'Österreich', 'country_code': 'at'}, 'boundingbox': ['47.3022786', '47.3034032', '10.0364416', '10.0373858']}
The most eastern location in 2020 was in Gemeinde Schoppernau, Österreich on May, 10
Out[26]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [27]:
location_south_geo = geolocator.reverse(location_south)
if debug:
    print(location_south_geo.raw)
for p in potentialplacename:
    if location_south_geo.raw.get('address').get(p):
        name_south = location_south_geo.raw.get('address').get(p)
print('The southmost location in %s was in '
      '%s, %s on %s' % (whichyear,
                        name_south,
                        location_south_geo.raw.get('address').get('country'),
                        locations[locations.eq(location_south[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d')))
m = folium.Map(location=[float(location_south_geo.raw.get('lat')),
                         float(location_south_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_south_geo.raw.get('lat')),
                              float(location_south_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_south).add_to(m)
m
{'place_id': 57904828, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'node', 'osm_id': 4955051975, 'lat': '46.2937521', 'lon': '7.8812521', 'display_name': 'Vista Alpina Augenzentrum, 1a, Bahnhofplatz, Visp, Valais/Wallis, 3930, Schweiz/Suisse/Svizzera/Svizra', 'address': {'place': 'Vista Alpina Augenzentrum', 'house_number': '1a', 'road': 'Bahnhofplatz', 'town': 'Visp', 'county': 'Visp', 'state': 'Valais/Wallis', 'postcode': '3930', 'country': 'Schweiz/Suisse/Svizzera/Svizra', 'country_code': 'ch'}, 'boundingbox': ['46.2937021', '46.2938021', '7.8812021', '7.8813021']}
The southmost location in 2020 was in Visp, Schweiz/Suisse/Svizzera/Svizra on March, 28
Out[27]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [28]:
location_west_geo = geolocator.reverse(location_west)
if debug:
    print(location_west_geo.raw)
for p in potentialplacename:
    if location_west_geo.raw.get('address').get(p):
        name_west = location_west_geo.raw.get('address').get(p)
print('The most western location in %s was in '
      '%s, %s on %s' % (whichyear,
                        name_west,
                        location_west_geo.raw.get('address').get('country'),
                        locations[locations.eq(location_west[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d')))
m = folium.Map(location=[float(location_west_geo.raw.get('lat')),
                         float(location_west_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_west_geo.raw.get('lat')),
                              float(location_west_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_west).add_to(m)
m
{'place_id': 205519090, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 541357552, 'lat': '46.89581289702031', 'lon': '5.646605880522781', 'display_name': 'Route de Genève, Rabeur, Montholier, Dole, Jura, Bourgogne-Franche-Comté, France métropolitaine, 39800, France', 'address': {'road': 'Route de Genève', 'hamlet': 'Rabeur', 'village': 'Montholier', 'municipality': 'Dole', 'county': 'Jura', 'state': 'Bourgogne-Franche-Comté', 'country': 'France', 'postcode': '39800', 'country_code': 'fr'}, 'boundingbox': ['46.8941346', '46.8987636', '5.6436956', '5.6483394']}
The most western location in 2020 was in Rabeur, France on July, 18
Out[28]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [29]:
location_top_geo = geolocator.reverse(location_top)
if debug:
    print(location_top_geo.raw)
for p in potentialplacename:
    if location_top_geo.raw.get('address').get(p):
        name_top = location_top_geo.raw.get('address').get(p)
print('The highest location in %s was in '
      '%s, %s on %s' % (whichyear,
                        name_top,
                        location_top_geo.raw.get('address').get('country'),
                        locations[locations.eq(location_top[0]).any(1)]['Date'].tolist()[0].strftime('%B, %-d')))
m = folium.Map(location=[float(location_top_geo.raw.get('lat')),
                         float(location_top_geo.raw.get('lon'))],
               tiles=tileprovider,
               zoom_start=zoom_start*2)
folium.CircleMarker(location=[float(location_top_geo.raw.get('lat')),
                              float(location_top_geo.raw.get('lon'))],
                    radius=radius,
                    popup=name_top).add_to(m)
m
{'place_id': 165119899, 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright', 'osm_type': 'way', 'osm_id': 305223227, 'lat': '46.4105049', 'lon': '8.0745093', 'display_name': 'Schönbiel - Bettmerhorn (Bergstation), Bettmeralp, Östlich Raron, Valais/Wallis, 3992, Schweiz/Suisse/Svizzera/Svizra', 'address': {'road': 'Schönbiel - Bettmerhorn (Bergstation)', 'village': 'Bettmeralp', 'county': 'Östlich Raron', 'state': 'Valais/Wallis', 'postcode': '3992', 'country': 'Schweiz/Suisse/Svizzera/Svizra', 'country_code': 'ch'}, 'boundingbox': ['46.4085176', '46.4115559', '8.0717075', '8.0756119']}
The highest location in 2020 was in Bettmeralp, Schweiz/Suisse/Svizzera/Svizra on March, 17
Out[29]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [30]:
# Show the extreme values in the overview below or not
showextremes = True
In [31]:
# Plot *all* locations on a single map
m = folium.Map(location=[locations['Latitude'].mean(),
                         locations['Longitude'].mean()],
               tiles=tileprovider,
               zoom_start=zoom_start)
if showextremes:
    # Extreme locations
    folium.CircleMarker(location=location_average,
                        radius=radius,
                        popup='Average location in %s' % name_average).add_to(m)
    folium.CircleMarker(location=location_north,
                        radius=radius,
                        popup='Northmost location in %s' % name_north).add_to(m)
    folium.CircleMarker(location=location_east,
                        radius=radius,
                        popup='Northmost location in %s' % name_east).add_to(m)
    folium.CircleMarker(location=location_south,
                        radius=radius,
                        popup='Northmost location in %s' % name_south).add_to(m)
    folium.CircleMarker(location=location_west,
                        radius=radius,
                        popup='Northmost location in %s' % name_west).add_to(m)
    folium.CircleMarker(location=location_top,
                        radius=radius,
                        popup='Highest location (%s m) on the %s' % (locations[locations['Altitude'] == locations['Altitude'].max()].Altitude.values[0],
                                                                     name_top)).add_to(m)
# All locations, in different ways
singlepoints = False
fast = True
if singlepoints:
    for c, loc in locations.iterrows():
        # not every point, but every x-th one, or else the map is too slow
        if not c % 10:
            folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                                radius=2,
                                popup='%s@%s' % (loc.Date, loc.Time),
                                color='darkred'
                               ).add_to(m)
else:
    if fast:
        # FastMarkerCluster
        m.add_child(folium.plugins.FastMarkerCluster(locations[['Latitude', 'Longitude']].values.tolist()))
    else:
        # Markercluster
        mc = folium.plugins.MarkerCluster()
        for c, loc in locations.iterrows():
            mc.add_child(folium.CircleMarker(location=[loc.Latitude, loc.Longitude],
                                             popup='%s@%s' % (loc.Date, loc.Time)))
        m.add_child(mc)
m.save('map-points.html')
m
Out[31]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [32]:
# Viridis colormap from here: https://www.thedataschool.co.uk/gwilym-lockwood/viridis-colours-tableau/
gradient={0.00: '#440154FF',
          0.05: '#481567FF',
          0.10: '#482677FF',
          0.15: '#453781FF',
          0.20: '#404788FF',
          0.25: '#39568CFF',
          0.30: '#33638DFF',
          0.35: '#2D708EFF',
          0.40: '#287D8EFF',
          0.45: '#238A8DFF',
          0.50: '#1F968BFF',
          0.55: '#20A387FF',
          0.60: '#29AF7FFF',
          0.65: '#3CBB75FF',
          0.70: '#55C667FF',
          0.75: '#73D055FF',
          0.80: '#95D840FF',
          0.85: '#B8DE29FF',
          0.90: '#DCE319FF',
          0.95: '#FDE725FF'}
In [33]:
# Show a heatmap instead of single points
m = folium.Map(location=[locations['Latitude'].mean(),
                         locations['Longitude'].mean()],
               tiles=tileprovider,
               zoom_start=zoom_start)
showextremes=False
if showextremes:
    # Extreme locations
    folium.CircleMarker(location=location_average,
                        radius=radius,
                        popup='Average location in %s' % name_average,
                       ).add_to(m)
    folium.CircleMarker(location=location_north,
                        radius=radius,
                        popup='Northmost location in %s' % name_north,
                       ).add_to(m)
    folium.CircleMarker(location=location_east,
                        radius=radius,
                        popup='Most eastern location in %s' % name_east,
                       ).add_to(m)
    folium.CircleMarker(location=location_south,
                        radius=radius,
                        popup='Southmost location in %s' % name_south,
                       ).add_to(m)
    folium.CircleMarker(location=location_west,
                        radius=radius,
                        popup='Most western location in %s' % name_west,
                       ).add_to(m)
    folium.CircleMarker(location=location_top,
                        radius=radius,
                        popup='Highest location (%s m) on the %s' % (locations[locations['Altitude'] == locations['Altitude'].max()].Altitude.values[0],
                                                                     name_top),
                       ).add_to(m)
# Add heatmap
folium.plugins.HeatMap(locations[['Latitude', 'Longitude']].values.tolist(),
                       gradient=gradient).add_to(m)
m.save('map-heat.html')
m
Out[33]:
Make this Notebook Trusted to load map: File -> Trust Notebook