pythonfolium

Folium put markers in marker clusters AND in layers based on a value


So, I'm working with a dataset of stores, each store with its lat, lng, name and category. Since we are talking about several hundreds of even thousands of stores, I'm using marker clusters, and they are working fine...

Now, I need to also set these stores in different layers based on their category, so that when I click on say "electronics stores", I only get those stores in the map (and they should be removed from the marker cluster as well)

Consider this sample data:

stores = [(-23.5578906,-46.6665546, 'store1','electronics'),
             (-23.562711,-46.674363, 'store2','home goods'),
             (-23.5642399,-46.6681833, 'store3','beauty'),
             (-23.584167,-46.678497, 'store4','electronics'),
             (-23.5956238,-46.6865377, 'store5','electronics'),
             (-23.5868682,-46.6773554,'store6','home goods'), 
             (-23.6011096,-46.6739275, 'store7','beauty'),
             (-23.6087354,-46.6973713, 'store8','home goods'),
             (-23.5943515,-46.6846959, 'store9','beauty')]

My code works ok for putting the markers in clusters, but when I try to also add them to layers based on their categories it doesn't work. I get no errors, and the map "loads", but the markers and clusters don't get displayed, and I get no layers on the map.

This is my code:

    mymap = folium.Map(location=[y_map, x_map], zoom_start=11,tiles=None)
    folium.TileLayer(name="Mapbox Bright",control=False).add_to(mymap)

    markers_list = []
    all_gp = []
    for lat, lng, name, category zip(df_stores['LAT'], 
                                                  df_stores['LNG'],
                                                  df_stores['NAME'],
                                                  df_stores['CATEGORY']
                                              ):
        html = '''NAME: ''' + name + '''<br>CATEGORY: ''' + category
            
        iframe = folium.IFrame(html,
                               width=300,
                               height=130)

        popup = folium.Popup(iframe,
                                 max_width=300)
        
         
        lead_marker = folium.Marker(
                [lat, lng],   
                popup=popup,
                icon=folium.Icon(color='purple', icon='glyphicon-cutlery', prefix='glyphicon')
        )
        markers_list.append(lead_marker)
        
        pg = category
        all_gp.append(pg)
        
    mCluster = MarkerCluster(name="Stores").add_to(mymap)
    
    for pnt in markers_list:
        pnt.add_to(mCluster)

######################################################################
    # Create point_layer object
    unique_gp = list(set(all_gp))
    vlist = []
    for i,k in enumerate(unique_gp):
        locals()[f'point_layer{i}'] = folium.FeatureGroup(name=k)
        vlist.append(locals()[f'point_layer{i}'])
        
    # Creating list for point_layer
    pl_group = []
    for n in all_gp:
        for v in vlist: 
            if n == vars(v)['layer_name']:
                pl_group.append(v)
                
    for pnt,pg in zip(markers_list,pl_group):
        pnt.add_to(pg)
        pg.add_to(mymap)
######################################################################   
        
    folium.LayerControl().add_to(mymap) 
    mymap.add_child(MeasureControl()) 
    mymap.render()
    mymap.save('stores.html')

The code between the lines of ############ I took form another post here (How to add categorical layered data to LayerControl() in python Folium map?) and adapted it to my code, but it seems I'm missing something. If I take out the last for cycle from the code, the map loads correctly with its clusters working ok, any suggestions?


Solution

  • I will answer with the understanding that the question is how to create a category layer, add markers for the information that belongs to it, and control the show/hide with a layer control. First, set the respective column data from the row information in the data frame and add the pop-up information. Add the category information based on the category information to the pre-prepared per-category layer.

    import pandas as pd
    import numpy as np
    import folium
    from folium.plugins import MarkerCluster
    
    stores = [(-23.5578906,-46.6665546, 'store1','electronics'),
                 (-23.562711,-46.674363, 'store2','home goods'),
                 (-23.5642399,-46.6681833, 'store3','beauty'),
                 (-23.584167,-46.678497, 'store4','electronics'),
                 (-23.5956238,-46.6865377, 'store5','electronics'),
                 (-23.5868682,-46.6773554,'store6','home goods'), 
                 (-23.6011096,-46.6739275, 'store7','beauty'),
                 (-23.6087354,-46.6973713, 'store8','home goods'),
                 (-23.5943515,-46.6846959, 'store9','beauty')]
    
    df = pd.DataFrame(stores, columns=['LAT','LNG','NAME','CATEGORY'])
    
    mymap = folium.Map(location=[df['LAT'].mean(), df['LNG'].mean()], zoom_start=12)
    
    #mCluster = MarkerCluster(name="Stores").add_to(mymap)
    mCluster_hg = MarkerCluster(name="home goods").add_to(mymap)
    mCluster_ele = MarkerCluster(name="electronics").add_to(mymap)
    mCluster_bea = MarkerCluster(name="beauty").add_to(mymap)
    
    for row in df.itertuples():
        #print(row)
        location = row[1], row[2]
        icon=folium.Icon(color='purple', icon='glyphicon-cutlery', prefix='glyphicon')
        html = '''NAME: ''' + row[3] + '''<br>CATEGORY: ''' + row[4]
        iframe = folium.IFrame(html, width=300, height=130)
        popup = folium.Popup(iframe, max_width=300)
        marker = folium.Marker(location=location, popup=popup, icon=icon)
        #folium.Popup(popup).add_to(marker)
        #mCluster_bea.add_child(marker)
        if row[4] == 'electronics':
            mCluster_ele.add_child(marker)
        elif row[4] == 'home goods':
            mCluster_hg.add_child(marker)
        elif row[4] == 'beauty':
            mCluster_bea.add_child(marker)        
    
    folium.LayerControl().add_to(mymap);
    
    mymap
    

    enter image description here