Folium: Custom Markers only work with URLs

Created on 24 Aug 2017  路  11Comments  路  Source: python-visualization/folium

It seems that custom markers only work with URLs and not local image files.

This works:

icon = folium.features.CustomIcon('http://www.pngall.com/wp-content/uploads/2016/05/Iron-Man.png', icon_size=(50,50))
folium.Marker([43, -79],
              popup='Iron Man',
              icon=icon
              ).add_to(geo_map)

This does not work:

icon = folium.features.CustomIcon('Iron-Man.png', icon_size=(50,50))
folium.Marker([43, -79],
              popup='Iron Man',
              icon=icon
              ).add_to(geo_map)

Most helpful comment

Ok I see. It seems like the utility function that parses images for CustomIcon (image_to_url) no longer supports BytesIO format in the current version. However, it supports the path! (so it will transform the file automatically to Bytes for you). What I did is directly pass the path of the image:

icon_path = r"C:\some_path\icon.png"
icon = folium.features.CustomIcon(icon_image=icon_path ,icon_size=icons_size)

marker=folium.Marker([row["coord"].y,row["coord"].x],popup=popup,icon=icon).add_to(feature_groups[alert_icon_name])

All 11 comments

If the Iron-Man.png served along side the map? If not It won't work. If true and it does not work we have a bug.

I can confirm everything works as expected, closing this.

screenshot from 2017-09-18 10-56-05

Maybe we could add a self-contained version that would encode the image in the HTML. I do have a goal to do that for everything in folium in a consistent way, but it will take a while.

If you want to send a PR to solve that for icons take a look at the ImageOverlay plugin and try to implement something along those lines.

@nanodan this code will work with local image file.

import base64

encoded = base64.b64encode(open('Iron-Man.png', 'rb').read())
decoded = base64.b64decode(encoded)
icon_url = BytesIO(decoded)
icon = folium.features.CustomIcon(icon_url, icon_size=(50,50))
folium.Marker([43, -79],
              popup='Iron Man',
              icon=icon
              ).add_to(geo_map)

but for list of markers, the code only shows the first icon. :(

@dvu4 Thank you for sharing! That worked for me

@ocefpaf could you please explain how you serve local files to folium?

@nanodan I have solved this problem by using @dvu4 answer and then doing deep copies of the objects (so it isn't needed to parse each element each time):

import copy
m = folium.Map()
icon = BytesIO(base64.b64decode(base64.b64encode(open(os.path.join(os.getcwd(),"icons","Weather_Icons_05_hail-512.png"), 'rb').read())))
for iteration in range(10):
      marker_icon = copy.copy(icon)
      folium.Marker(location=[temp_coord[iteration][0], temp_coord[iteration][1],icon=marker_icon ).add_to(m)

but for list of markers, the code only shows the first icon. :(

This has come up in #744 as well. Though it is expected behavior at the moment that an icon has to be created for each marker, PR's to improve on this are welcome.

I tried @dvu4 suggestion but it results in a TypeError: Object of type 'BytesIO' is not JSON serializable

Is there a better method for achieving this, or are custom icons still not supported?

@nathan3leaf please paste the full traceback. I think I faced that error too. Let's see if I can help you

Traceback (most recent call last):
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\threading.py", line 916, in _bootstrap_inner
    self.run()
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "C:/Users/natha/Dropbox/PYTHON_PROJECTS/analysisSuite.py", line 13453, in runAnalysis
    self.createInteractiveMap(centerName=sites.text(), coords=[lat, lon])
  File "C:/Users/natha/Dropbox/PYTHON_PROJECTS/analysisSuite.py", line 12556, in createInteractiveMap
    MAPPING().getInteractiveMap(centerName=centerName, coords=[lat, lon], layers=layers, output=False)
  File "C:/Users/natha/Dropbox/PYTHON_PROJECTS/analysisSuite.py", line 10994, in getInteractiveMap
    clientIcon = folium.features.CustomIcon(icon_url, icon_size=(50, 50))
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\site-packages\folium\features.py", line 1146, in __init__
    self.icon_url = image_to_url(icon_image)
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\site-packages\folium\utilities.py", line 102, in image_to_url
    url = json.loads(json.dumps(image))
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Users\natha\AppData\Local\Programs\Python\Python36-32\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'BytesIO' is not JSON serializable

Thank you @davidolmo your help is very much appreciated.

Ok I see. It seems like the utility function that parses images for CustomIcon (image_to_url) no longer supports BytesIO format in the current version. However, it supports the path! (so it will transform the file automatically to Bytes for you). What I did is directly pass the path of the image:

icon_path = r"C:\some_path\icon.png"
icon = folium.features.CustomIcon(icon_image=icon_path ,icon_size=icons_size)

marker=folium.Marker([row["coord"].y,row["coord"].x],popup=popup,icon=icon).add_to(feature_groups[alert_icon_name])

@davidolmo well, you are correct. I was able to make some modifications using the method you posted and it's working perfectly. Thanks for the helpful info!

thank you @davidolmo this really helped me.....

Was this page helpful?
5 / 5 - 1 ratings

Related issues

olibchr picture olibchr  路  19Comments

ispmarin picture ispmarin  路  17Comments

agravier picture agravier  路  26Comments

FlorianHoevelmann picture FlorianHoevelmann  路  14Comments

nathan3leaf picture nathan3leaf  路  32Comments