Folium: View image on popup

Created on 12 Mar 2017  Â·  13Comments  Â·  Source: python-visualization/folium

I've been trying to add an image to a folium marker popup using the following command:

html = '<img src="image.png" style="width:400px;height:300px;">'
folium.Marker(location=(lat, lon), popup=folium.Popup(folium.element.IFrame(html=html, width=420, height=320), max_width=2000)).add_to(map)

Each time I open the saved "map.html" file in the browser and click on the marker, however, the popup shows an empty white rectangle without the image.

I even tried serving the file using "python3 -m http.server 8080" and navigating to the address "127.0.0.1:8080/map.html", but I still see just the empty white rectangle.

Note that the file "image.png" is in the same directory as the "map.html" file.

Could you please let me know what I might be doing wrong? I've now been stuck with this for a few hours.

Thanks!

Most helpful comment

That ( plus the _.decode()_ ) did the trick! Thank you very much.

All 13 comments

Your safest bet is to use base64 to encode the PNG and ensure it will be displayed in the Jupyter notebook. Here is an example: http://nbviewer.jupyter.org/gist/ocefpaf/992b4790ced1a740b1cb075ca814c2b9

But I admit that the situation could be improved.

Works! Thanks so much for this.

Quick followup to this. Would encoding using base64 be necessary even when trying to display non-raster image formats (say SVG) on a popup?

Had no idea I could do this. Thanks again. Really appreciate your help with this!

@ocefpaf
I attempted to replicate these steps for locally saved (in same directory as the "map.html) jpg photos. Clicking on the points opens a white rectangle popup but displays a 'broken link' symbol when opening with Chrome.

I followed your process from the following line (your Jupyter cell 4) onward:
encoded = base64.b64encode(open(png, 'rb').read())

But in my case, instead of 'png' I read the filename of my jpg.
The code behind the broken link reads:
"data:image/jpg;base64,b'/9j/4AAQSkZJRgAB....."

Any ideas what I might be doing wrong? Thanks.

Can you share a sscce?

@ocefpaf
Sure. Here is a simplified version of my code (apologies if this is not ideal sscce format - I tried). Simplified in that I have replaced the part at the start with arbitrary inputs where in the full version lat/lon/etc are read from photo exif data. Same applies to values of width/height/res in the lower section for now. To run this you will just need three .jpg's saved in the current directory.

For me, this generates the html map with 3 points in the correct position, but clicking them shows a white rectangle with a broken link (and also causes the map to pan away from the points).

import pandas
import os
import folium
from folium import IFrame
import base64


filelist = []
for photos in os.listdir(os.curdir):
    if photos.endswith(".jpg"):
            filelist.append(photos)

latlist = [51.50,51.51,51.50]
lonlist = [-0.01,0,0.01]

index = range(1,len(filelist)+1)
columns = ['Filename','Lat','Lon']         
df = pandas.DataFrame(index=index, columns=columns)

df['Filename']=filelist
df['Lat']=latlist
df['Lon']=lonlist

#Create map object:
map=folium.Map(location=[df['Lat'].mean(),df['Lon'].mean()],zoom_start=13,tiles='Stamen Terrain')

for lat,lon,Filename in zip(df['Lat'],df['Lon'],df['Filename']):
    encoded = base64.b64encode(open(Filename, 'rb').read())
    html = '<img src="data:image/jpg;base64,{}">'.format
    resolution, width, height = 75, 50, 25
    iframe = IFrame(html(encoded), width=(width*resolution)+20, height=(height*resolution)+20)
    popup = folium.Popup(iframe, max_width=1000)
    icon = folium.Icon(color="red", icon="ok")
    marker = folium.Marker(location=[lat, lon], popup=popup, icon=icon)
    marker.add_to(map)

map.save(outfile='TestMap.html')

EDIT: So it was just the specified width/height parameters which was causing the panning when clicking on the point (popup was too big for screen). Reducing these solves that. But I still haven't solved the broken link.

The line '<img src="data:image/jpg;base64,{}">'.format must be '<img src="data:image/jpeg;base64,{}">'.format (note the jpeg vs jpg).

See http://nbviewer.jupyter.org/gist/ocefpaf/0ec5c93138744e5072847822818b4362

That ( plus the _.decode()_ ) did the trick! Thank you very much.

The decode should be needed only on Python 3 BTW.
.decode()

So basically it looks like this:
Filename ='abc.jpg'
encoded = base64.b64encode(open(Filename, 'rb').read())
html='《img src="data:image/jpeg;base64,{}"》'.format #replace 《》with <>
resolution, width, height = 75, 50, 25
iframe = IFrame(html(encoded.decode('UTF-8')), width=(widthresolution)+20, height=(heightresolution)+20)
popup = folium.Popup(iframe, max_width=1000)
icon = folium.Icon(color="red", icon="ok")
marker = folium.Marker(location=[37.426, -122.085], popup=popup, icon=icon)
marker.add_to(m)

@ChenghaoChenCPP
Thanks a lot! .decode('UTF-8') solved my issue!
Thanks again.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aviogit picture aviogit  Â·  4Comments

sanga picture sanga  Â·  3Comments

jgoad picture jgoad  Â·  4Comments

ghandic picture ghandic  Â·  5Comments

siezyj picture siezyj  Â·  3Comments