Folium — это библиотека Python для создания интерактивных веб-карт на основе JavaScript-библиотеки Leaflet.js.
На самом деле, мы уже много раз использовали Folium ранее — когда работали с методом explore() у GeoDataFrame. Внутри GeoPandas этот метод автоматически создаёт интерактивную карту именно с помощью Folium.
Теперь мы перейдём к более гибкой и детальной настройке карт напрямую через библиотеку Folium.
В этом разделе мы создадим интерактивную карту со следующими слоями:
границы района;
землепользование;
станции метро;
зоны пешеходной доступности (5, 10 и 15 минут) для станций.
import geopandas as gpd
import folium0.2 Подготовка данных¶
В этом примере будем использовать четыре набора пространственных данных, которые мы заранее подготовили для Василеостровского района Санкт-Петербурга. Данные лежат в нашем репозитории:
area.geojson- границы района;landuse.geojson- полигоны землепользования;metro.geojson- станции метро;isochrones.geojson- зоны пешеходной доступности до станций
0.2.1. Границы района¶
Читаем файл с границами района.
area = gpd.read_file("data/area.geojson")Смотрим структуру данных.
area.head()Отображаем слой на карте.
area.explore(tiles="cartodbpositron")0.2.2. Землепользование¶
Загружаем данные по землепользованию.
landuse = gpd.read_file("data/landuse.geojson")Смотрим структуру.
landuse.head()Отображаем на карте
landuse.explore(tiles="cartodbpositron")0.2.3. Станции метро¶
Читаем данные
stations = gpd.read_file("data/metro.geojson")Смотрим на структуру
stations.head()Отображаем на карте
stations.explore(tiles="cartodbpositron")0.2.4. Зоны доступности¶
Читаем данные
isochrones = gpd.read_file("data/isochrones.geojson")Смотрим на структуру
isochrones.head()Отображаем на карте
isochrones.explore(tiles="cartodbpositron")1. Создание базовой карты¶
Прежде чем добавлять на карту тематические слои — границу района, землепользование, станции метро и изохроны — нужно создать основу карты.
На этом шаге мы:
определим, в какой точке карта должна открываться;
зададим начальный масштаб;
выберем фоновую подложку;
создадим объект карты 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
)
m2. Добавление слоёв¶
Базовая карта уже создана, но пока она содержит только фоновую подложку.
Теперь мы будем постепенно добавлять на неё пространственные данные в виде отдельных слоёв.
В 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)
m2.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: int642.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"].
Внутри функции происходит несколько шагов:
Из атрибутов объекта извлекается значение поля
landuse.По словарю
landuse_groupsопределяется, к какой укрупнённой группе относится данный тип землепользования.Для найденной группы подбирается цвет из словаря
landuse_colors.Функция возвращает словарь со стилем отображения объекта на карте.
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)
m2.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)
m2.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)
m3. Управление картой¶
После добавления всех тематических слоёв настроим элементы управления картой.
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 Итоговая карта¶
Отображаем готовую интерактивную карту.
m4.2 Сохранение карты¶
Сохраняем карту в HTML-файл. После этого карту можно открыть в браузере
# m.save("index.html")Итог¶
В этом разделе мы создали интерактивную веб-карту с несколькими слоями.
Мы:
загрузили и проверили данные;
создали базовую карту;
добавили тематические слои;
настроили стили и подсказки;
добавили элементы управления;
сохранили карту в HTML.