Search code examples
pythonpandasfolium

Python Folium - Looking to add multiple Markers, each with their own JPEG / PNG


I'm looking to build a simple Folium interactive map using Python. Within the map there will be multiple Markers, and each marker will have a JPEG / PNG in the popup.

I have successfully added a single Marker with JPEG, using this code:

csv_file = 'Location List.csv'
lat = 51.001591
long = -3.034212
png = '2.jpg'
tooltip = "Click me!"
resolution, width, height = 200, 10, 5
base_location = 'V:/CalibrationLocations/'
location_location = f'{base_location}/Location List'
image_location = f'{base_location}/Images'
extension = 'jpg'

html = '''
<h1 style="color:#61666b;size:48">MBES Data Example Image</h1>
<br>
<img src="data:image/jpeg;base64,{}">
<br>'''.format

os.chdir(location_location)
df = pd.read_csv(csv_file)
os.chdir(image_location)


def create_map():

    encoded = base64.b64encode(open(png, 'rb').read()).decode('UTF-8')
    iframe = IFrame(html(encoded), width=(width * resolution) + 20, height=(height * resolution) + 20)
    popup = folium.Popup(iframe, max_width=2650)
    icon = folium.Icon(color="red", icon="ok")
    marker = folium.Marker(location=[lat, long], popup=popup, icon=icon)
    m = folium.Map(location=[lat, long], zoom_start=5)
    marker.add_to(m)
    os.chdir(base_location)
    m.save("index.html")
    return m


if __name__ == '__main__':
    map_layers = create_map()

I have also successfully created a Pandas DataFrame from a CSV file and added multiple markers, using this code:

def create_map():
    m = folium.Map(location=[lat, long], zoom_start=5)
    df.apply(lambda row: folium.Marker([row["Latitude"], row["Longitude"]], popup=row['ID']).add_to(m), axis=1)

    os.chdir(base_location)
    m.save("index.html")
    return m

I have tried the below code, which is a hybrid of the first two functions, but it only plots one Marker, not the 4 in the CSV file. It also no longer has a JPEG / PNG in the popup.

def create_map():

    encoded = base64.b64encode(open(png, 'rb').read()).decode('UTF-8')
    iframe = IFrame(html(encoded), width=(width * resolution) + 20, height=(height * resolution) + 20)
    popup = folium.Popup(iframe, max_width=2650)
    icon = folium.Icon(color="red", icon="ok")
    m = folium.Map(location=[lat, long], zoom_start=5)
    df.apply(lambda row: folium.Marker([row["Latitude"], row["Longitude"]], popup=popup).add_to(m), axis=1)

    os.chdir(base_location)
    m.save("index.html")
    return m

Has anyone succesfully plotted multiple Markers, each with a JPEG / PNG in the popup?


Solution

  • For anyone wondering, I managed to solve this by creating a list of objects for the popup (based on the number of image files in a folder) and then parsed through this list to create each marker.

    Code below in three (3) *.py files:

    MAC_Main.py

    from folium import Map, Marker, LatLngPopup, plugins
    import os
    
    from MAC_DictionaryList import latitude_list, longitude_list,max_lat, min_lat, max_long, min_long
    from MAC_Variables import base_location, start_lat, start_long, popup_objects, icon_objects
    
    def generate_map(lat, long):
        return Map([lat, long], template = 'template.html')
    
    
    def add_layers(latitude, longitude, popup_object, icon_object):
        base_map.add_child(Marker([latitude, longitude], popup=popup_object, icon=icon_object))
        return base_map
    
    
    def position_marker(map_layer):
        return map_layer.add_child(LatLngPopup())
    
    
    def mini_map(map_name):
        minimap = plugins.MiniMap()
        map_name.add_child(minimap)
    
    
    def find_home(map_name):
        plugins.LocateControl().add_to(map_name)
        plugins.Geocoder().add_to(map_name)
    
    
    def fit_bounds(map_name):
        map_name.fit_bounds([[min_lat, min_long], [max_lat, max_long]])
        map_name.add_child(plugins.MeasureControl())
    
    
    def save_map(html_name):
        os.chdir(base_location)
        base_map.save(html_name)
    
    
    if __name__ == '__main__':
        base_map = generate_map(start_lat, start_long)
    
        for lat, long, popup, icon in zip(latitude_list, longitude_list, popup_objects, icon_objects):
            add_layers(lat, long, popup, icon)
        position_marker(base_map)
        mini_map(base_map)
        find_home(base_map)
        fit_bounds(base_map)
        save_map('MAC_Locations_2.html')
    

    MAC_Variables.py

    from folium import IFrame, Popup, Icon
    import base64
    from glob import glob
    import os
    
    def shorten(file):
        shortname = os.path.splitext(os.path.basename(file))[0]
        return shortname
    
    
    # ---------- MAP VARIABLES -----------
    start_lat = 54.7
    start_long = 006.1
    file_extension = 'jpg'
    resolution, width, height = 180, 5, 5
    final_width = (width * resolution) + 20
    final_height = (height * resolution) + 20
    zoom_level = 6
    
    # ---------- FILE VARIABLES -----------
    base_location = 'Volumes/Python/CalibrationLocations/'
    image_location = f'{base_location}01 Images'
    png_list = glob(f'{image_location}/*.{file_extension}')
    
    
    # ---------- HTML -----------
    html = '''
    <h1 style="color:#61666b;size:48">{}</h1>
    <br>
    <img src="data:image/jpeg;base64,{}">
    <br>'''.format
    
    
    # ---------- OBJECTS -----------
    popup_objects = [(Popup(IFrame(html(shorten(png_image), base64.b64encode(open(png_image, 'rb').read()).decode('UTF-8')), width=final_width, height=final_height), max_width=2650)) for png_image in png_list]
    icon_objects = [(Icon(color="red", icon="ok")) for png_image in png_list]
    

    MAC_DictionaryList.py

    location_dictionary = {'Location 1': {'Latitude': 54.5, 'Longitude': 1.9},
                       'Location 2': {'Latitude': 52, 'Longitude': 2.3},
                       'Location 3': {'Latitude': 54.7, 'Longitude': 5.7},
                       'Location 4': {'Latitude': 56, 'Longitude': 4.6}
                       }
    
    latitude_list = []
    longitude_list = []
    
    for key, value in location_dictionary.items():
        latitude_list.append(value['Latitude'])
        longitude_list.append(value['Longitude'])
    
    max_lat = max(latitude_list)
    min_lat = min(latitude_list)
    
    max_long = max(longitude_list)
    min_long = min(longitude_list
    
    )