Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Folium — это библиотека Python для создания интерактивных веб-карт на основе JavaScript-библиотеки Leaflet.js.

На самом деле, мы уже много раз использовали Folium ранее — когда работали с методом explore() у GeoDataFrame. Внутри GeoPandas этот метод автоматически создаёт интерактивную карту именно с помощью Folium.

Теперь мы перейдём к более гибкой и детальной настройке карт напрямую через библиотеку Folium.

В этом разделе мы создадим интерактивную карту со следующими слоями:

  • границы района;

  • землепользование;

  • станции метро;

  • зоны пешеходной доступности (5, 10 и 15 минут) для станций.

0. Импорт библиотек и подготовка данных

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

import geopandas as gpd
import folium

0.2 Подготовка данных

В этом примере будем использовать четыре набора пространственных данных, которые мы заранее подготовили для Василеостровского района Санкт-Петербурга. Данные лежат в нашем репозитории:

  • area.geojson - границы района;

  • landuse.geojson - полигоны землепользования;

  • metro.geojson - станции метро;

  • isochrones.geojson - зоны пешеходной доступности до станций

0.2.1. Границы района

Читаем файл с границами района.

area = gpd.read_file("data/area.geojson")

Смотрим структуру данных.

area.head()
Loading...

Отображаем слой на карте.

area.explore(tiles="cartodbpositron")
Loading...

0.2.2. Землепользование

Загружаем данные по землепользованию.

landuse = gpd.read_file("data/landuse.geojson")

Смотрим структуру.

landuse.head()
Loading...

Отображаем на карте

landuse.explore(tiles="cartodbpositron")
Loading...

0.2.3. Станции метро

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

stations = gpd.read_file("data/metro.geojson")

Смотрим на структуру

stations.head()
Loading...

Отображаем на карте

stations.explore(tiles="cartodbpositron")
Loading...

0.2.4. Зоны доступности

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

isochrones = gpd.read_file("data/isochrones.geojson")

Смотрим на структуру

isochrones.head()
Loading...

Отображаем на карте

isochrones.explore(tiles="cartodbpositron")
Loading...

1. Создание базовой карты

Прежде чем добавлять на карту тематические слои — границу района, землепользование, станции метро и изохроны — нужно создать основу карты.

На этом шаге мы:

  1. определим, в какой точке карта должна открываться;

  2. зададим начальный масштаб;

  3. выберем фоновую подложку;

  4. создадим объект карты Folium, в который позже будем добавлять слои.

1.1. Определяем центр карты

Чтобы карта сразу открывалась на нужной территории, нужно задать её центр. Для этого мы вычислим геометрический центр района.

center = area.geometry.centroid.iloc[0]
center_lat = center.y
center_lon = center.x

print(center_lat, center_lon)
59.94304698542129 30.23891924658615
/tmp/ipykernel_2618/1297056537.py:1: 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.

  center = area.geometry.centroid.iloc[0]

1.2. Создаём объект карты

Теперь создадим базовую карту Folium:

  • folium.Map() создаёт интерактивную веб-карту;

  • location задаёт центр карты;

  • zoom_start задаёт начальный уровень приближения (зума);

  • tiles выбирает фоновую подложку;

  • control_scale добавляет масштабную линейку на карту.

m = folium.Map(
    location=[center_lat, center_lon],
    zoom_start=12,
    tiles="cartodb positron",
    control_scale=True
)

m
Loading...

2. Добавление слоёв

Базовая карта уже создана, но пока она содержит только фоновую подложку.

Теперь мы будем постепенно добавлять на неё пространственные данные в виде отдельных слоёв.

В Folium данные обычно добавляются как объекты GeoJson.

Общий принцип выглядит так:

folium.GeoJson(
    данные,
    параметры_отображения
).add_to(m)

2.1. Границы района

Начнём с самого базового слоя — границы района. Он нам пригодится, чтобы обозначить территорию исследования

2.1.1. Настройка стиля

Параметр style_function вызывается отдельно для каждого объекта GeoJSON (feature). Объект feature содержит геометрию и атрибуты объекта в feature["properties"].

Функция стилизации должна возвращать словарь с параметрами отображения объекта на карте:

  • fillColor — цвет заливки полигона;

  • color — цвет границы;

  • weight — толщина линии;

  • fillOpacity — прозрачность заливки;

  • opacity — прозрачность контура;

  • dashArray — делает линию пунктирной.

area_style = lambda feature: {
    "fillColor": "#64748B",
    "color": "#334155",
    "weight": 2,
    "fillOpacity": 0.03,
    "opacity": 0.65,
    "dashArray": "6, 5",
}

2.1.2. Добавление GeoJSON-слоя

Добавим слой на карту

folium.GeoJson(
    area,
    name="Граница района",
    style_function=area_style,
).add_to(m)

m
Loading...

2.2. Землепользование

Теперь перейдём к более сложному тематическому слою — землепользованию. В отличие от предыдущих примеров, здесь данные содержат несколько категорий объектов с разными типами использования территории. Поэтому перед настройкой отображения сначала посмотрим, какие категории присутствуют в наборе данных, а при необходимости объединим некоторые из них в более крупные группы.

2.2.1. Анализ категорий

Для начала определим, какие типы землепользования представлены в данных.

landuse["landuse"].value_counts()
landuse grass 1808 residential 153 commercial 63 industrial 47 forest 45 construction 30 flowerbed 16 garages 14 religious 8 military 6 retail 6 recreation_ground 5 cemetery 4 brownfield 2 farmland 1 Name: count, dtype: int64

2.2.2. Группировка категорий

Чтобы упростить визуализацию и сделать карту более читаемой, объединим близкие по смыслу категории в несколько укрупнённых групп. Для этого создадим словарь соответствий между исходными типами землепользования и новыми группами.

landuse_groups = {
    "residential": "residential",

    "commercial": "commercial",
    "retail": "commercial",

    "industrial": "industrial",
    "construction": "industrial",
    "garages": "industrial",
    "brownfield": "industrial",

    "grass": "green",
    "recreation_ground": "green",
    "flowerbed": "green",
    "farmland": "green",

    "forest": "forest",

    "religious": "special",
    "cemetery": "special",
    "military": "special",
}

2.2.3. Цвета для групп

Для каждой группы зададим отдельный цвет.

landuse_colors = {
    "residential": "#fdd49e",
    "commercial": "#fc8d59",
    "industrial": "#d7301f",
    "green": "#78c679",
    "forest": "#238443",
    "special": "#756bb1",
}

2.2.4. Функция стилизации

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

Функция landuse_style(feature) вызывается отдельно для каждого объекта GeoJSON. В аргумент feature передаётся текущий объект слоя вместе с его геометрией и атрибутами. Атрибуты объекта находятся в словаре feature["properties"].

Внутри функции происходит несколько шагов:

  1. Из атрибутов объекта извлекается значение поля landuse.

  2. По словарю landuse_groups определяется, к какой укрупнённой группе относится данный тип землепользования.

  3. Для найденной группы подбирается цвет из словаря landuse_colors.

  4. Функция возвращает словарь со стилем отображения объекта на карте.

def landuse_style(feature):

    landuse_type = feature["properties"].get("landuse")

    landuse_class = landuse_groups.get(landuse_type, "other")

    color = landuse_colors.get(landuse_class, "#d9d9d9")

    return {
        "fillColor": color,
        "color": "#ffffff",
        "weight": 0.4,
        "fillOpacity": 0.25,
        "opacity": 0.6,
    }

2.2.5. Настройка всплывающих подсказок

Добавим всплывающие подсказки (tooltip), которые будут отображаться при наведении курсора на объект.

В подсказке будет выводиться поле landuse, содержащее исходный тип землепользования. Параметр aliases задаёт подпись поля, а localize=True позволяет корректно форматировать значения.

landuse_tooltip = folium.GeoJsonTooltip(
    fields=["landuse"],
    aliases=["Тип землепользования:"],
    localize=True
)

2.2.6. Добавление слоя на карту

Теперь добавим слой землепользования на карту. Для отображения используется folium.GeoJson, которому передаются данные слоя, функция стилизации и всплывающие подсказки.

Параметр style_function=landuse_style означает, что для каждого объекта GeoJSON будет вызываться созданная ранее функция стилизации. Она автоматически определяет цвет и параметры отображения объекта на основе его атрибутов.

folium.GeoJson(
    landuse,
    name="Землепользование",
    style_function=landuse_style,
    tooltip=landuse_tooltip
).add_to(m)

m
Loading...

2.3. Изохроны доступности

Изохроны ограничивают территорию, которую можно достичь за определённое время. В нашем примере используются зоны доступности для разных временных интервалов: 5, 10 и 15 минут.

2.3.1. Определяем стили для зон

Сначала создадим словарь со стилями отображения для каждой изохроны. Ключами словаря выступают значения времени в секундах:

  • 300 — 5 минут;

  • 600 — 10 минут;

  • 900 — 15 минут.

Для каждой зоны задаются параметры отображения линии:

  • color — цвет контура;

  • weight — толщина линии;

  • opacity — прозрачность.

isochrone_styles = {
    300: {
        "color": "#475569",
        "weight": 3.5,
        "opacity": 0.95,
    },
    600: {
        "color": "#64748B",
        "weight": 3,
        "opacity": 0.85,
    },
    900: {
        "color": "#94A3B8",
        "weight": 2.5,
        "opacity": 0.75,
    },
}

2.3.2. Функция стилизации

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

Как и в предыдущих примерах, функция получает объект feature — отдельный GeoJSON-объект слоя вместе с его атрибутами. В данном случае в атрибутах хранится значение времени доступности.

Из поля feature["properties"]["value"] извлекается значение времени в секундах:

  • 300 — 5 минут;

  • 600 — 10 минут;

  • 900 — 15 минут.

Далее по словарю isochrone_styles подбираются параметры отображения для соответствующей зоны. Если значение отсутствует в словаре, используется стиль по умолчанию.

Функция возвращает словарь параметров отображения линии изохроны.

def isochrone_style(feature):
    value = int(feature["properties"].get("value", 0))
    style = isochrone_styles.get(value, {
        "color": "#9CA3AF",
        "weight": 2,
        "opacity": 0.7,
    })

    return {
        "fill": False,
        "color": style["color"],
        "weight": style["weight"],
        "opacity": style["opacity"],
    }

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

Перед добавлением слоя подготовим набор данных для отображения на карте.

Сначала создадим отдельный GeoDataFrame iso_layer, в который включим только необходимые поля:

  • station_name — название станции;

  • value — время доступности в секундах;

  • geometry — геометрия изохрон.

После этого приведём поле value к целочисленному типу и дополнительно создадим новое поле minutes, в котором время будет храниться уже в минутах. Это поле удобно использовать в подсказках и подписях на карте.

iso_layer = isochrones[["station_name", "value", "geometry"]].copy()

iso_layer["value"] = iso_layer["value"].astype(int)
iso_layer["minutes"] = (iso_layer["value"] / 60).astype(int)

2.3.4. Настройка всплывающих подсказок

Для изохрон добавим всплывающие подсказки (tooltip), которые будут отображаться при наведении курсора на объект.

В подсказке выводятся:

  • station_name — название станции;

  • minutes — время доступности в минутах.

Параметр aliases задаёт подписи полей, а sticky=True фиксирует подсказку рядом с курсором.

iso_tooltip=folium.GeoJsonTooltip(
    fields=["station_name", "minutes"],
    aliases=["Станция:", "Минут пешком:"],
    sticky=True
)

2.3.5. Добавление слоя на карту

Добавим подготовленный слой изохрон на карту с помощью folium.GeoJson.

Параметр style_function=isochrone_style отвечает за основной стиль линий изохрон. Для каждой геометрии Folium вызывает функцию isochrone_style, которая подбирает цвет, толщину и прозрачность линии по значению времени доступности.

folium.GeoJson(
    iso_layer,
    name="Изохроны",
    style_function=isochrone_style,
    tooltip=iso_tooltip
).add_to(m)

m
Loading...

2.4. Станции метро

Последний слой — станции метро.

В отличие от предыдущих примеров, здесь используются точечные объекты. Для таких данных обычно применяются маркеры.

2.4.1. Стилизация точек

Для отображения станций будем использовать folium.CircleMarker — круговые маркеры с настраиваемым размером и стилем.

В данном примере задаются:

  • radius — размер маркера;

  • color — цвет границы;

  • weight — толщина границы;

  • fill — включение заливки;

  • fill_color — цвет заливки;

  • fill_opacity — прозрачность заливки.

metro_markers = folium.CircleMarker(
    radius=6,
    color="#FFFFFF",
    weight=2,
    fill=True,
    fill_color="#334155",
    fill_opacity=1,
)

2.4.2. Настройка всплывающих подсказок

Для станций метро также добавим всплывающие подсказки (tooltip), которые будут отображаться при наведении курсора на точку.

В подсказке выводится поле name, содержащее название станции. Параметр aliases задаёт подпись поля, а sticky=True фиксирует подсказку рядом с курсором.

metro_tooltip = folium.GeoJsonTooltip(
    fields=["name"],
    aliases=["Станция:"],
    sticky=True
)

2.4.3. Добавление слоя на карту

Теперь добавим слой станций метро на карту.

Для отображения точечных объектов используется folium.GeoJson, которому передаются:

  • stations — набор геоданных со станциями метро;

  • marker=metro_markers — стиль точечных маркеров, созданный ранее;

  • tooltip=metro_tooltip — всплывающие подсказки с названиями станций.

metro_layer = folium.GeoJson(
    stations,
    name="Станции метро",
    marker=metro_markers,
    tooltip=metro_tooltip,
).add_to(m)

m
Loading...

3. Управление картой

После добавления всех тематических слоёв настроим элементы управления картой.

3.1 Переключатель слоёв

Добавляем панель управления слоями. С её помощью пользователь может включать и выключать отдельные слои карты.

folium.LayerControl(collapsed=False).add_to(m)
<folium.map.LayerControl at 0x7f1d1adb8050>

LayerControl позволяет включать и выключать слои. Параметр collapsed=False делает панель слоёв раскрытой по умолчанию.

3.2 Координаты курсора

Добавляем отображение координат курсора. Теперь при наведении мыши на карту пользователь будет видеть широту и долготу точки.

from folium.plugins import MousePosition

MousePosition().add_to(m)
<folium.plugins.mouse_position.MousePosition at 0x7f1d1ada4dd0>

3.3 Полноэкранный режим

Параметры:

  • position="bottomright" размещает кнопку в правом нижнем углу;

  • title задаёт подпись при наведении на кнопку;

  • title_cancel задаёт подпись для выхода из полноэкранного режима;

  • force_separate_button=True делает кнопку отдельным элементом интерфейса.

from folium.plugins import Fullscreen

Fullscreen(
    position="bottomright",
    title="Открыть на весь экран",
    title_cancel="Выйти из полноэкранного режима",
    force_separate_button=True,
).add_to(m)
<folium.plugins.fullscreen.Fullscreen at 0x7f1d1739dc50>

3.4 Мини-карта

Мини-карта помогает понять, где находится текущий фрагмент карты относительно более крупной территории.

from folium.plugins import MiniMap


MiniMap(tile_layer="cartodbpositron", toggle_display=True).add_to(m)
<folium.plugins.minimap.MiniMap at 0x7f1d173b7810>

4. Просмотр и сохранение карты

На этом этапе карта полностью готова.

Мы добавили:

  • тематические слои;

  • стилизацию объектов;

  • всплывающие подсказки;

  • элементы управления картой.

Теперь можно посмотреть итоговый результат и сохранить карту как HTML-файл.

4.1 Итоговая карта

Отображаем готовую интерактивную карту.

m
Loading...

4.2 Сохранение карты

Сохраняем карту в HTML-файл. После этого карту можно открыть в браузере

# m.save("index.html")

Итог

В этом разделе мы создали интерактивную веб-карту с несколькими слоями.

Мы:

  • загрузили и проверили данные;

  • создали базовую карту;

  • добавили тематические слои;

  • настроили стили и подсказки;

  • добавили элементы управления;

  • сохранили карту в HTML.