python4oceanographers

Turning ripples into waves

Custom icons in folium

We had an interesting problem. How to create a map with SECOORA's assets showing all the buoys, gliders, HF-radars, and land stations as an interactive map?

To accomplish that we had to use a specific folium PR, that will be part of the next release, with the new custom icon class. This new class allow users to display custom images as icons instead of the default markers.

Here is how to do it. First we instantiate the map:

In [3]:
import folium

lon, lat = -86.276, 30.935 
zoom_start = 5

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

In another post I will explain how I created the GeoJSON below. For now it is suffice to say that they hold all the information we need to construct the map.

In [4]:
import json

with open('data/stations.geojson') as f:
    stations = json.load(f)

with open('data/hfradar.geojson') as f:
    hfradar = json.load(f)

The icons URLs, the popup message, and the Point positions are defined in the GeoJSON. The only information that is not there is the icon size.

In [5]:
icon_size = (14, 14)

for feature in stations['features']:
    lon, lat = feature['geometry']['coordinates']
    icon_url = feature['properties']['icon']
    popup = feature['properties']['popupcontent']
    
    icon = folium.features.CustomIcon(icon_url,
                                      icon_size=(14, 14))
    
    marker = folium.map.Marker([lat, lon], icon=icon,
                               popup=folium.map.Popup(popup))
    mapa.add_children(marker)

And now do the same thing, but for the HF-radar GeoJSON. Note that in this case we also have a Polygon feature in there. The polygon represents the radar range radius. We are trowing away the polygon styling though. The style information is coded according the simplestyle-spec. We do plan to use simplestyle-spec styling options soon.

In [6]:
style_function = lambda feature: dict(fillColor='#DEFFDE',
                                      color='#AECCAE',
                                      weight=1,
                                      opacity=1)

for feature in hfradar['features']:
    if feature['geometry']['type'] == 'Point':
        lon, lat = feature['geometry']['coordinates']
        icon_url = feature['properties']['icon']
        popup = feature['properties']['popupcontent']
        
        icon = folium.features.CustomIcon(icon_url,
                                          icon_size=(14, 14))
        marker = folium.Marker([lat, lon], icon=icon,
                                   popup=folium.Popup(popup))
        mapa.add_children(marker)
    elif feature['geometry']['type'] == 'Polygon':
        gjson = folium.features.GeoJson(feature, style_function=style_function)
        
        mapa.add_children(gjson)
In [7]:
mapa
Out[7]:

Aside from the ugly range polygon that is pretty cool!

Special thanks to Martin Journois for the awesome PR that made this possible.

In [8]:
HTML(html)
Out[8]:

This post was written as an IPython notebook. It is available for download or as a static html.

Creative Commons License
python4oceanographers by Filipe Fernandes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://ocefpaf.github.io/.

Comments