VI. Веб-карта с Folium#

Folium — это библиотека Python для создания интерактивных веб-карт на основе Leaflet.js. С её помощью можно легко визуализировать геопространственные данные, добавлять маркеры, всплывающие подсказки, хлороплетные карты, а также расширять функциональность с помощью плагинов.

Основные возможности Folium:

  • Создание интерактивных карт с набором нескольких слоев

  • Добавление маркеров, кружков, всплывающих подсказок и кластеров

  • Построение картограмм (Choropleth)

  • Подключение плагинов (MiniMap, MarkerCluster, HeatMap и др.)

В это разделе мы создадим интерактивную карту театров Санкт-Петербурга

Импортируем библиотеки

import folium
import geopandas as gpd

0. Подготовка данных#

Читаем данные

theaters = gpd.read_file('data/spb_theaters.geojson')
admin_district = gpd.read_file('data/spb_admin.gpkg', layer="okrug")

Посчитаем кол-во театров по районам города

# приведем данные в одну систему координат
if theaters.crs != admin_district.crs:
    theaters = theaters.to_crs(admin_district.crs)

# Пространственное пересечение
theaters_within_district = gpd.sjoin(theaters, admin_district, how="left", predicate="within")

# Группировка и подсчёт
theaters_count = theaters_within_district.groupby('NAME').size().reset_index(name='theaters_count')

# Соединяем данные со слоем с районами по полю  NAME
admin_district_with_count = admin_district.merge(
    theaters_count,
    on='NAME', 
    how='left'
)

# Посчитаем кол-во театров на 100 000 ччеловек
admin_district_with_count['theatersPerPop'] = admin_district_with_count['theaters_count']/(admin_district_with_count['Popul']/100000)


# Поcмотрим на данные
admin_district_with_count.head()
NAME Popul geometry theaters_count theatersPerPop
0 округ Пискарёвка 61706.0 MULTIPOLYGON (((30.35925 59.99390, 30.37635 59... 1.0 1.620588
1 Смолячково 742.0 MULTIPOLYGON (((29.42981 60.18954, 29.45195 60... NaN NaN
2 Молодёжное 1685.0 MULTIPOLYGON (((29.45195 60.20537, 29.45554 60... NaN NaN
3 Серово 272.0 MULTIPOLYGON (((29.48220 60.22101, 29.48917 60... NaN NaN
4 Кронштадт 44374.0 MULTIPOLYGON (((29.63402 60.03155, 29.63406 60... NaN NaN

1. Настройка карты#

  • Внимательно рассмотрите функцию, попробуйте понять, за что отвечает каждая переменная

data = admin_district_with_count.to_crs('EPSG:4326')
m = folium.Map(location=[data.centroid.y.mean(), data.centroid.x.mean()], zoom_start=10,  tiles="cartodb positron", control_scale=True)
/var/folders/ry/9bb7wrz54vq_kn2ytlj6ynzm0000gn/T/ipykernel_60143/2365336728.py:2: UserWarning: Geometry is in a geographic CRS. Results from 'centroid' are likely incorrect. Use 'GeoSeries.to_crs()' to re-project geometries to a projected CRS before this operation.

  m = folium.Map(location=[data.centroid.y.mean(), data.centroid.x.mean()], zoom_start=10,  tiles="cartodb positron", control_scale=True)
  • Изучите область карты. Понадобятся ли изменения?

m
Make this Notebook Trusted to load map: File -> Trust Notebook

2. Добавление картограммы#

folium.Choropleth(
    name='Theaters Choropleth',
    geo_data=admin_district_with_count,
    data=admin_district_with_count,
    columns=['NAME', 'theatersPerPop'],
    fill_color='YlGnBu',
    fill_opacity = 0.5,
    key_on='feature.properties.NAME',
    nan_fill_color='lightgray',
    nan_fill_opacity=0.4,
   line_color = "white",
   legend_name="Theaters per 100 000 "
).add_to(m)
<folium.features.Choropleth at 0x15652b910>
  • Посмотрим на карту

m
Make this Notebook Trusted to load map: File -> Trust Notebook

3. Добавление подсказки (tooltip)#

folium.GeoJson(
    admin_district_with_count,
    name="Districts with tooltips",
    style_function=lambda x: {
        'fillColor': 'transparent',
        'color': 'transparent',
        'weight': 0
    },
    tooltip=folium.GeoJsonTooltip(
        fields=['NAME', 'theaters_count'],
        aliases=['Округ:', 'Количество театров:'],
        localize=True
    )
).add_to(m)
<folium.features.GeoJson at 0x15652abf0>
m
Make this Notebook Trusted to load map: File -> Trust Notebook
  • Посмотрим на карту

4. Добавление точек в виде маркеров и их кластеризация#

  • Импортируем плагин

from folium.plugins import MarkerCluster, FeatureGroupSubGroup
  • Добавляем маркеры и возможность их кластеризации

theaters = theaters[~(theaters.geometry.isna() | theaters.is_empty)]

# Создаём MarkerCluster и SubGroup
marker_cluster = MarkerCluster(name='Theaters').add_to(m)
mc1 = FeatureGroupSubGroup(marker_cluster, 'Theaters').add_to(m)

# Добавляем каждый театр как Marker
for idx, row in theaters.iterrows():
    # Координаты
    lat = row.geometry.y
    lon = row.geometry.x
    
    # Пример popup: имя театра + адрес
    popup_text = row['name']
    
    # Tooltip при наведении (можно упростить)
    tooltip_text = row['name']
    
    # Маркер с кастомной иконкой
    folium.Marker(
        location=[lat, lon],
        popup=popup_text,
        tooltip=tooltip_text,
        icon=folium.Icon(icon='heart', prefix='glyphicon', color='darkblue')
    ).add_to(mc1)
  • Посмотрим на карту

m
Make this Notebook Trusted to load map: File -> Trust Notebook

5. Добавление плагинов/виджетов#

  • Импортируем плагины

from folium.plugins import MousePosition
from folium.plugins import Fullscreen
  • Добавляем контроль слоёв

folium.LayerControl().add_to(m)
<folium.map.LayerControl at 0x164238400>
  • Добавлеям координаты курсора

MousePosition().add_to(m)
<folium.plugins.mouse_position.MousePosition at 0x164239fc0>
  • Добавлеям полноэкранный режим

Fullscreen(
    position="bottomright",
    title="Expand me",
    title_cancel="Exit me",
    force_separate_button=True,
).add_to(m)
<folium.plugins.fullscreen.Fullscreen at 0x16423ab00>
  • Смотрим на карту

m
Make this Notebook Trusted to load map: File -> Trust Notebook

6. Сохраняем результат#

m.save("index.html")