Создание интерактивной карты с помощью Streamlit и Folium в Python
Клиенту нужен был скрипт Python, большинство из которых я привожу здесь, для создания интерактивного веб-приложения. Для этого проекта я выбрал библиотеки Streamlit и Folium. Он только хотел иметь возможность запускать программу локально на своем рабочем столе. Цель этого приложения — отобразить карту с маркерами для конкретных объектов недвижимости в США, которые хранятся в нескольких файлах CSV; клиенту нужен визуальный инструмент.
Сначала скрипт импортирует необходимые библиотеки и загружает CSV-файлы в фреймы данных Pandas. Он также определяет некоторые функции для получения информации о широте и долготе на основе сокращений штатов и для обработки пользовательских событий на карте.
Затем скрипт создает карту с помощью Folium и устанавливает некоторые параметры по умолчанию. Затем он использует боковую панель в библиотеке Streamlit, чтобы добавить некоторые параметры фильтрации для свойств, отображаемых на карте, например фильтрацию по владельцу и состоянию.
Наконец, скрипт добавляет на карту маркеры для выбранных свойств и отображает карту в приложении Streamlit с помощью функции st_folium. Полученное веб-приложение позволяет пользователям исследовать объекты на карте и взаимодействовать с ними.
Сначала я поделюсь своим скриптом, который я фактически отправил заказчику с некоторыми изменениями, затем я поделюсь версией Pythonic, написанной ChatGPT.
import streamlit as st import folium import pandas as pd from streamlit_folium import st_folium from folium import features st.set_page_config(layout="wide") df_states = pd.read_csv('states.csv') def get_pos(lat,lng): return lat,lng def get_lat_lon(abbrev): row = df_states[df_states["Abbreviation"] == abbrev] return (row["Latitude"].values[0], row["Longitude"].values[0]) if row.shape[0] else (None, None) df_i = pd.read_csv('ind_ll.csv') df_i = df_i[df_i['latitude'] > 0] df_i.reset_index(drop=True, inplace=True) print(df_i.shape) print(df_i.head()) df_p = pd.read_csv('prologis_ll.csv') df_p = df_p[df_p['latitude'] > 0] df_p.reset_index(drop=True, inplace=True) print(df_p.shape) print(df_p.head()) # Filter by owner prologis_owners = df_p['True Owner Name'].unique().tolist() add_select = st.sidebar.selectbox("Filter Owner", [*['All'], *prologis_owners]) prologis_states = df_p['State'].unique().tolist() add_state = st.sidebar.selectbox("Filter State", [*['US'], *sorted(prologis_states)]) # Create the map m = folium.Map(location=[39.063946, -76.802101], zoom_start=5) if add_select != 'All': df_p = df_p[df_p['True Owner Name'] == add_select] if add_state != 'US': df_p = df_p[df_p['State'] == add_state] # example usage latitude, longitude = get_lat_lon(add_state) if add_state == 'FL': scale = 7 longitude = longitude + 4 elif add_state == 'GA': scale = 7 longitude = longitude + 6 elif add_state == 'IL': scale = 7 longitude = longitude + 6 elif add_state == 'IN': scale = 7 longitude = longitude + 6 elif add_state == 'KY': scale = 7 longitude = longitude + 6 elif add_state == 'MD': scale = 9 longitude = longitude + 2 elif add_state == 'MO': scale = 7 longitude = longitude + 6 elif add_state == 'MS': scale = 7 longitude = longitude + 6 elif add_state == 'NC': scale = 7 longitude = longitude + 6 elif add_state == 'NJ': scale = 9 longitude = longitude + 2 elif add_state == 'NY': scale = 7 longitude = longitude + 4 latitude = latitude + 1 elif add_state == 'OH': scale = 7 longitude = longitude + 6 elif add_state == 'PA': scale = 7 longitude = longitude + 6 elif add_state == 'SC': scale = 8 longitude = longitude + 2 elif add_state == 'TN': scale = 7.5 longitude = longitude + 4 elif add_state == 'VA': scale = 7 longitude = longitude + 6 elif add_state == 'TX': scale = 6 longitude = longitude + 7 else: scale = 10 m = folium.Map(location=[latitude, longitude], zoom_start=scale) # Add a marker for each city in the dataframe, with a popup showing the city name and population for i, row in df_p.iterrows(): address = row['Property Address'] city = row['City'] message = f'{address}, {city}' lat = row['latitude'] lng = row['longitude'] folium.Marker([lat, lng], popup=message).add_to(m) def get_lat_lng(event=None, id=None, properties=None): lat = event["coordinates"][0] lng = event["coordinates"][1] print(f"Latitude: {lat}, Longitude: {lng}") add_mark = folium.LatLngPopup() st_data = st_folium(m, width = 2400)
Далее, вот версия Pythonic, написанная ChatGPT.
import streamlit as st import folium import pandas as pd from streamlit_folium import st_folium from folium import features st.set_page_config(layout="wide") # Load data from CSV files df_states = pd.read_csv('states.csv') df_i = pd.read_csv('ind_ll.csv').query('latitude > 0').reset_index(drop=True) df_p = pd.read_csv('prologis_ll.csv').query('latitude > 0').reset_index(drop=True) # Define helper functions def get_lat_lng(event=None, id=None, properties=None): lat, lng = event["coordinates"] print(f"Latitude: {lat}, Longitude: {lng}") def get_lat_lon(abbrev): row = df_states[df_states["Abbreviation"] == abbrev] return tuple(row[["Latitude", "Longitude"]].values[0]) if not row.empty else (None, None) # Create the map with default options m = folium.Map(location=[39.063946, -76.802101], zoom_start=5) # Add filters to the sidebar prologis_owners = df_p['True Owner Name'].unique().tolist() add_select = st.sidebar.selectbox("Filter Owner", ['All'] + prologis_owners) prologis_states = ['US'] + sorted(df_p['State'].unique().tolist()) add_state = st.sidebar.selectbox("Filter State", prologis_states) # Apply filters to the data and update the map if add_select != 'All': df_p = df_p[df_p['True Owner Name'] == add_select] if add_state != 'US': df_p = df_p[df_p['State'] == add_state] # Adjust map options based on state state_options = {'FL': (7, 4), 'GA': (7, 6), 'IL': (7, 6), 'IN': (7, 6), 'KY': (7, 6), 'MD': (9, 2), 'MO': (7, 6), 'MS': (7, 6), 'NC': (7, 6), 'NJ': (9, 2), 'NY': (7, 4), 'OH': (7, 6), 'PA': (7, 6), 'SC': (8, 2), 'TN': (7.5, 4), 'VA': (7, 6), 'TX': (6, 7)} scale, longitude = state_options.get(add_state, (10, 0)) latitude, _ = get_lat_lon(add_state) if latitude: m = folium.Map(location=[latitude, longitude], zoom_start=scale) # Add markers to the map for each property in the filtered dataset for _, row in df_p.iterrows(): address = row['Property Address'] city = row['City'] message = f'{address}, {city}' lat, lng = row['latitude'], row['longitude'] folium.Marker([lat, lng], popup=message).add_to(m) # Display the map in the Streamlit app st_data = st_folium(m, width=2400)
Вот краткое изложение изменений, внесенных ChatGPT:
- Удалены ненужные импорты и назначения для
features
из Folium. - Использовали связанные методы для фильтрации и сброса индекса фреймов данных
df_i
иdf_p
. - Упрощена функция
get_pos
для возврата кортежа вместо назначения переменных. - Изменен оператор
if
в функцииget_lat_lon
, чтобы использоватьnot row.empty
вместоrow.shape[0]
. - Удалены операторы
print
, используемые для отладки. - Создание карты
m
перемещено за пределы оператораif
в фильтреadd_state
и добавлена проверка допустимого значения широты перед обновлением местоположения карты. - Создан словарь под названием
state_options
для хранения настроек масштаба и долготы для каждого штата. - Изменено создание полей выбора
add_select
иadd_state
для использования понимания списка с шаблонами['All'] +
и['US'] + sorted()
соответственно. - Используется распаковка кортежей для упрощения функции
get_lat_lng
. - Изменен цикл
for
в фильтреadd_state
, чтобы использовать_
в качестве переменной для неиспользуемого значения индекса. - Для ясности переименовал переменную
st_data
вmap_data
. - Добавлены комментарии по всему коду для документирования каждого изменения.
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .