'How can I make a list in a popup in a map with folium?

I am using pandas and folium to display different companies for each unique city in a Dataframe.

The first dataframe is something like this:

city count id company_name geo_loc lat lon
0 USA 2 7254 Advanced Heat Treat Corp. (42.7756032, -94.1956133) 39.783730 -94.1956133
1 Cedar Rapids, Iowa, United States 4 7254 Advanced Heat Treat Corp. (39.7837304, -100.445882) 39.7837304 -100.445882
2 Humboldt, Iowa, United States 2 7254 Corn Belt Power Cooperative (39.7837304, -100.445882) 39.7837304 -100.445882
3 Humboldt, Iowa, United States 4 7258 Corridor Careers (42.5361805, -92.447758) 42.5361805 -92.447758

The second one is something like this. With just the necessary information:

city company_name
0 Cedar Falls, Iowa, United States Far Reach , Martin Bros
1 Cedar Rapids, Iowa, United States Collabrance , Corridor Careers
2 Davenport, Iowa, United States McCarthy Improvement
3 Des Moines, Iowa, United States Flynn Wright , Iowa Public Radio , Medico ...
4 Humboldt, Iowa, United States Corn Belt Power Cooperative
#Necessary libraries
import folium
import pandas as pd
import numpy as np
from geopy.geocoders import Nominatim
import folium

#Reading csv and obtaining locations
data = pd.read_csv('test.csv',error_bad_lines = False)
geolocator = Nominatim(user_agent= 'app')
locations = pd.DataFrame({'Name': data['city'].unique()})
lat_lon = []
for location in data['city']:
    location = geolocator.geocode(location,timeout=100)
    if location is None:
        lat_lon.append(np.nan)
    else:
        geo = (location.latitude, location.longitude)
        lat_lon.append(geo)

data['geo_loc'] = lat_lon

#Unique values
Comp_locations = pd.DataFrame(data['city'].value_counts().reset_index())

#Grouping to obtain just city and the companies
Companies = data.groupby('city')['company_name'].unique()
Companies_2 = Companies.to_frame().reset_index()
Companies_2 = Companies_2.rename(columns= {0: 'city',1: 'companies'})

Comp_locations.columns = ['city', 'count']
Companies_locations = Comp_locations.merge(data, on='city', how='right').dropna()

lat,lon = zip(*np.array(Companies_locations['geo_loc']))
Companies_locations['lat'] = lat
Companies_locations['lon'] = lon

#Bluemarkers to indicate each city
m = folium.Map(tiles="OpenStreetMap", zoom_start=2)
Companies_locations["count"] = Companies_locations["count"].astype(str) 
for i in range(0,len(Companies_locations)):
   folium.Marker(
      location=[Companies_locations.iloc[i]['lat'], Companies_locations.iloc[i]['lon']],
      popup=Companies_locations.iloc[i]['city'],
   ).add_to(m)
m

This is what I have with bluemarkers City marks

Add marker one by one on the map. This is to show the companies names

for i in range(0,len(Companies_locations)):
    html=f"""
        <h1> {Companies_locations.iloc[i]['count']}</h1>
        <p>Companies:</p> 
        <ul>      
           <li>{Companies_2.iloc[i]['company_name']}<li>
        </ul>
        </p>
        <p>And here the company  <a href="{Companies_locations.iloc[i]['url']}" target = "_blank">link </a></p>

        """
    iframe = folium.IFrame(html=html, width=200, height=200)
    popup = folium.Popup(iframe, max_width=2650)
    folium.Marker(
        location=[Companies_locations.iloc[i]['lat'], Companies_locations.iloc[i]['lon']],
        popup=popup,
        icon=folium.DivIcon(html=f"""
            <div><svg>
                <circle cx="5" cy="5" r="4" fill="#69b3a2" opacity="0.4"/>
                <rect x="3", y="3" width="3" height="3", fill="red", opacity=".3" 
            </svg></div>""")
    ).add_to(m)
    m

This is what I have with the popups. For each bullet-mark I desire to display the companies names (the number above is the quatinty of companies in this city).

Popups with names

But I have the following error:

"IndexError: single positional indexer is out-of-bounds"

How can I manage my previous Dataframe to iterate over it and print each company with a bullet mark?



Solution 1:[1]

I have never used geopy, so I looked for sample data to show your assignment in code without it. I got the sample data from here and created the code. I have company information in the columns of the data frame I used, so I added a new loop process and concatenated the html strings to create the bullet points.

import folium
import pandas as pd
import numpy as np
import folium

# sample data from https://uscompanydata.com/california-business-list/
data = pd.read_csv('./data/Company-Database-Sample.csv', sep=',')

data = data[['Company Name', 'Job Title', 'City','State', 'Zip', 'County Code', 'Area Code', 'Founded', 'Website Address', 'Employee ', 'Latitude', 'Longitude']]

data.dropna(subset=['Latitude', 'Longitude'], inplace=True)
data.reset_index(drop=True, inplace=True)

data.head()
    Company Name    Job Title   City    State   Zip     County Code     Area Code   Founded     Website Address     Employee    Latitude    Longitude
0   Phillips Chrysler Jeep Dodge    General Manager     Ocala   FL  34471   12083.0     352     1997.0  www.phillipschrysler.com    37  29.153831   -82.125527
1   Industrial Conveyor Systems     Chief Executive Officer     Cutler Bay  FL  33157   12086.0     305     1979.0  www.icsequipment.com    10  25.593898   -80.359226
2   Prism Optical Inc   Owner   Miami   FL  33168   12086.0     305     1959.0  www.prismoptical.com    9   25.875858   -80.210274
3   Piaggio America Inc.    President   West Palm Bch   FL  33406   12099.0     561     2004.0  www.piaggioaero.com     5   26.678277   -80.079994
4   A Busy Traveler Transportation  Owner   Merritt Island  FL  32954   12009.0     321     1994.0  www.abusytraveler.com   8   28.357230   -80.694249

m = folium.Map(tiles="OpenStreetMap", location=[data['Latitude'].mean(), data['Longitude'].mean()], zoom_start=7)

for i in range(len(data)):
    profiles = ''
    for info in data.loc[i,['Company Name','Job Title','Employee ','Founded']]:
        item = '<{0}>{1}</{0}>'.format('li',info)
        profiles += item
    #print(profiles)
    html=f"""
        <h1>{data.iloc[i]['Zip']}</h1>
        <p>Companies:</p> 
        <ul>
        {profiles}
        </ul>
        </p>
        <p>And here the company  <a href="{data.iloc[i]['Website Address']}" target = "_blank">link </a></p>
        """
    
    iframe = folium.IFrame(html=html, width=300, height=250)
    popup = folium.Popup(iframe, max_width=2650)
    folium.Marker(
        location=[data.iloc[i]['Latitude'], data.iloc[i]['Longitude']],
        popup=popup,
        icon=folium.DivIcon(html=f"""
            <div><svg>
                <circle cx="5" cy="5" r="4" fill="#69b3a2" opacity="0.7"/>
                <rect x="3", y="3" width="3" height="3", fill="red", opacity=".7" 
            </svg></div>""")
    ).add_to(m)
m

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 r-beginners