Строим карту бесплатных точек доступа Wi-Fi в Москве, прокладываем маршрут московского марафона, создаем интерактивную карту регионов РФ и хороплет-карту штатов США по COVID-19 с помощью блокнотов Jupyter, библиотек pandas, gmaps, ipyleaflet и folium.
Рассмотрим три библиотеки по работе с геоданными: gmaps, ipyleaflet и более продвинутую по сравнению с предыдущими – folium. Забегая вперед, скажем, что лучше использовать folium, так как в ней удобнее строить интерактивные карты и работать со слоями. В конце статьи вы найдете ссылки на блокноты с кодом.
pip install notebook
Запустим блокноты Jupyter:
jupyter notebook
Автоматически откроется страница по адресу http://localhost:8888/tree. Затем создадим новый блокнот, кликнув по кнопке New.
Помимо gmaps нам понадобятся инструменты интерактивного управления ipywidgets, widgetsnbextension и библиотека для обработки и анализа данных pandas. Они устанавливаются как через консоль (pip install), так и прямо из блокнота через восклицательный знак (!pip install):
!pip install gmaps
!pip install pandas
!pip install widgetsnbextension
Активируем виджеты следующими командами:
!jupyter nbextension enable --py --sys-prefix widgetsnbextension
!jupyter nbextension enable --py --sys-prefix gmaps
Рис. 1. Карта с маркерами точек WiFi (gmaps)
За основу возьмем датасет, размещенный на портале открытых данных Москвы, в котором содержится информация о 2.8 тыс. бесплатных точек Wi-Fi. На каждой 1001-й строчке датасета дублируются названия столбцов. Во избежание ошибок при обработке набора данных, удалим эти строчки из таблицы. Очищенный массив доступен в репозитории на Гитхабе.
Какую информацию возьмем из датасета? Нам нужны координаты (Latitude_WGS84, Longitude_WGS84), адрес (Location) и количество точек доступа (NumberOfAccessPoints).
Cоздадим список wifi_points, состоящий из словарей, в каждом из которых хранится вышеперечисленная информация о каждой точке. Затем создадим отдельный список marker_coordinates с координатами и переведем элементы списка из типа строка str в тип вещественное число float, потому что координаты – это число, а не строчка.
wifi_gmaps.ipynb import pandas as pd
import gmaps
file_name = 'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/data-9776-2020-12-21.csv'
df = pd.read_csv(file_name, sep=';', encoding='cp1251')
gmaps.configure(api_key='...')
wifi_points = []
i = 0
while i < len(df.index):
wifi_points.append({'Coordinates': [df['Latitude_WGS84'], df['Longitude_WGS84']], 'Location': df['Location'], 'NumberOfAccessPoints': df['NumberOfAccessPoints']})
i += 1
marker_coordinates = [wifi['Coordinates'] for wifi in wifi_points]
marker_coordinates = [[float(x) for x in y] for y in marker_coordinates] # здесь мы проходимся по элементами вложенных списков и меняем их типы со str на float
info_box_template = """
<dl>
<dt>Адрес:</dt><dd>{Location}</dd>
<dt>Количество точек доступа:</dt><dd>{NumberOfAccessPoints}</dd>
</dl>
"""
marker_info = [info_box_template.format(**points) for points in wifi_points]
marker_layer = gmaps.marker_layer(marker_coordinates, info_box_content=marker_info )
fig = gmaps.figure()
fig.add_layer(marker_layer)
fig
Здесь:
sep – разделитель между столбцами.
encoding – кодировка файла.
info_box_template – формирует HTML-форму с описанием точки Wi-Fi.
<dl> – создает контейнер.
<dt> – заголовок.
<dd> – описание.
marker_info – список, содержащий форматированные строчки с описанием точек Wi-Fi: адрес точки (Location) и количество работающих точек Wi-Fi (NumberOfAccessPoints).
marker_layer – создает слой маркеров с соответствующими координатами.
fig = gmaps.figure() – инициирует создание карты.
fig.add_layer(marker_layer) – добавляет слой с маркерами на карту.
fig – запускает карту.
Ошибка Figure(layout)
Если при запуске блокнота выскочила ошибка Figure(layout=FigureLayout(height='420px')), то перезапустите блокнот, но не через панель управления блокнотом (Kernel → Restart), а через консоль.
Установим библиотеки pandas, ipyleaflet и ipywidgets:
!pip install pandas
!pip install ipyleaflet
!pip install ipywidgets
Рис. 2. Карта с маркерами точек WiFi (ipyleaflet)
Создадим карту с точками Wi-Fi, но уже с помощью библиотеки ipyleaflet. Воспользуемся датасетом из раздела про gmaps:
import pandas as pd
from ipywidgets import HTML
from ipyleaflet import Map, Marker, Popup
file_name = 'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/data-9776-2020-12-21.csv'
df = pd.read_csv(file_name, sep=';', encoding='cp1251')
wifi_points = []
i = 0
while i < len(df.index):
wifi_points.append({'index': i, 'Coordinates': [df['Latitude_WGS84'], df['Longitude_WGS84']], 'Location': df['Location'], 'NumberOfAccessPoints': df['NumberOfAccessPoints']})
i += 1
marker_coordinates = [wifi['Coordinates'] for wifi in wifi_points]
marker_coordinates = [[float(x) for x in y] for y in marker_coordinates]
m = Map(center=(55.753215, 37.622504), zoom=11)
markers = [Marker(location=(marker_coordinates)) for i in range(len(marker_coordinates))]
info_box_template = """
<dl>
<dt>Адрес:</dt><dd>{Location}</dd>
<dt>Количество точек доступа:</dt><dd>{NumberOfAccessPoints}</dd>
</dl>
"""
locations_info = [info_box_template.format(**point) for point in wifi_points]
for i in range(len(markers)):
markers.popup = HTML(locations_info)
m.add_layer(markers)
m
Здесь:
markers – список из координат маркеров.
locations_info – список из адресов и количества точек Wi-Fi.
for i in range(len(markers)) – каждый из элементов на карте представляет из себя слой, поэтому напишем цикл создающий нужное количество слоев. Один слой – один маркер.
m – отрисовывает карту с маркерами.
Ошибка: виджеты не отображаются
Если виджеты не отображаются, перезапустите блокноты Jupyter через консоль.
Рис. 3. Маршрут 5 км московского марафона (ipyleaflet)
Построим маршрут 5 км московского марафона: импортируем из библиотеки ipyleaflet модуль «Муравьиный путь» AntPath и добавим маркеры Старт и Финиш!.
from ipyleaflet import AntPath, WidgetControl
from ipywidgets import IntSlider, jslink
m = Map(center=(55.718148, 37.555493), zoom=13)
marathon_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(marathon_path)
start_marker = Marker(location=(55.717435, 37.561014))
m.add_layer(start_marker)
finish_marker = Marker(location=(55.720267, 37.5558))
m.add_layer(finish_marker)
start = HTML()
finish = HTML()
start.value = "Старт"
finish.value = "Финиш!"
start_marker.popup = start
finish_marker.popup = finish
zoom_slider = IntSlider(description='Масштаб:', min=11, max=15, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
marathon_path – координаты марафона.
start_marker и finish_marker – координаты маркеров Старт и Финиш! соответственно.
start.value и finish.value – описания маркеров старта и финиша, которые появятся во всплывающем окне при клике на маркер.
zoom_slider – ползунок масштаба.
color – цвет линии.
pulse_color – цвет бегущих муравьев.
Рис. 4. Маршрут марафона с иконками AwesomeIcon (ipyleaflet)
Заменим стандартные иконки маркеров на иконки из каталога AwesomeIcon:
from ipyleaflet import AwesomeIcon
m = Map(center=(55.718148, 37.555493), zoom=14)
marathon_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(marathon_path)
start_icon = AwesomeIcon(
name='fa-play',
marker_color='green',
icon_color='white'
)
start_marker = Marker(icon=start_icon, location=(55.717435, 37.561014))
start = HTML()
start.value = "Старт"
start_marker.popup = start
m.add_layer(start_marker)
finish_icon = AwesomeIcon(
name='fa-stop',
marker_color='blue',
icon_color='black'
)
finish_marker = Marker(icon=finish_icon, location=(55.720267, 37.5558))
finish = HTML()
finish.value = "Финиш!"
finish_marker.popup = finish
m.add_layer(finish_marker)
zoom_slider = IntSlider(description='Масштаб:', min=11, max=17, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
start_icon и finish_icon – содержат элементы из библиотеки AwesomeIcon.
marker_color – цвет маркера.
icon_color – цвет иконки.
Рис. 5. Маршрут марафона с собственными иконками (ipyleaflet)
Добавим собственные иконки с помощью модуля Icon:
from ipyleaflet import Icon
from ipywidgets import IntSlider
m = Map(center=(55.718148, 37.555493), zoom=14)
ant_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(ant_path)
start_icon = Icon(icon_url='https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/5d6126a97905792c584b1f9e18cd8dd767ba2966/start.png', icon_size=[97, 36])
start_marker = Marker(icon=start_icon, location=(55.717435, 37.561014))
start = HTML()
start.value = "Старт"
start_marker.popup = start
m.add_layer(start_marker)
finish_icon = Icon(icon_url='https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/5d6126a97905792c584b1f9e18cd8dd767ba2966/finish.png', icon_size=[97, 36])
finish_marker = Marker(icon=finish_icon, location=(55.720267, 37.5558))
finish = HTML()
finish.value = "Финиш!"
finish_marker.popup = finish
m.add_layer(finish_marker)
zoom_slider = IntSlider(description='Масштаб:', min=11, max=17, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
Импортируем из библиотеки ipyleaflet модуль Icon, чтобы использовать собственные иконки.
icon_url– ссылка на иконку.
icon_size=[x, y] – задает размеры иконки: x – длина, y – высота.
Рис. 6. Карта 85 субъектов РФ (ipyleaflet)
Создадим карту с 85 субъектами РФ. Координаты границ субъектов возьмем из json-файла. Данные актуальны на 2015 год и в них есть дефект с Чукотским Автономным округом, но для нашей задачи – демонстрации возможностей библиотеки – этого вполне достаточно. Очищенная версия лежит в репозитории.
import os
import json
import random
import requests
from ipyleaflet import GeoJSON
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
m.add_layer(geo_json)
m
Здесь:
load_data – функция, которая записывает файл с данным в локальное хранилище.
random_color – функция, генерирующая случайные цвета для субъектов РФ.
style и hover_style – задают графическое отображение субъекта по умолчанию и при наведении на него курсора мыши.
Рис. 7. Интерактивная карта 85 субъектов РФ (ipyleaflet)
Сделаем карту интерактивной: при клике на субъект под картой появится название центрального города субъекта:
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
def handle_click(**kwargs):
print(kwargs['feature']['properties']['name'])
geo_json.on_click(handle_click)
m.add_layer(geo_json)
m
Здесь:
handle_click – функция, которая принимает именованные аргументы.
['name'] – имя субъекта.
geo_json.on_click(handle_click) – подключает к карте событие (вывод на экран) при клике на субъект.
Рис. 8. Интерактивная карта 85 субъектов РФ (ipyleaflet)
Теперь, с помощью функции handle_hover сделаем так, чтобы название центрального города субъекта появлялось при наведении курсора мыши на субъект:
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
def handle_hover(**kwargs):
print(kwargs['feature']['properties']['name'])
geo_json.on_hover(handle_hover)
m.add_layer(geo_json)
m
Здесь:
handle_hover – функция, принимающая именованные аргументы.
geo_json.on_click(handle_hover) – подключает к карте событие при наведении на субъект.
Рис. 9. Хороплет-карта карта США по COVID-19 (ipyleaflet)
Построим хороплет-карту (фоновая картограмма) штатов США по COVID-19. На хороплет-карте цветом с различной степенью насыщенности отображается интенсивность какого-либо показателя. Данные по заболеваемости возьмем из репозитория университета Джона Хопкинса, а координаты границ штатов с сайта библиотеки ipyleaflet. Слегка изменим csv-файл, добавив в него второй столбец State с почтовыми сокращениями штатов США (Alabama – AL и так далее), чтобы была связь со вторым ключом (id) для каждого штата из json-файла. Также удалим несколько штатов из csv-файла, границы которых отсутствуют в json-файле.
import ipyleaflet
from ipywidgets import link, FloatSlider
from branca.colormap import linear
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
geo_json_data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json',
'us-states_covid.json',
json.load)
confirmed = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv',
'03-13-2021_covid.csv',
pd.read_csv)
confirmed = dict(zip(confirmed['State'].tolist(), confirmed['Confirmed'].tolist()))
layer = ipyleaflet.Choropleth(
geo_data=geo_json_data,
choro_data=confirmed,
colormap=linear.YlOrRd_04,
border_color='black',
style={'fillOpacity': 0.8, 'dashArray': '5, 5'})
m = ipyleaflet.Map(center = (43,-100), zoom = 4)
m.add_layer(layer)
m
Здесь:
geo_json_data – загрузка json-файла с координатами границ штатов.
сonfirmed – загрузка csv-файла с данными по заболеваемости.
confirmed = dict... – создает словарь с ключем Почтовое название штата и значением Количество подтвержденных случаев заражения.
geo_data – координаты границ штатов.
choro_data – хороплет-данные, количество заболевших в каждом штате.
colormap – цвет из палитры ColorBrewer.
!pip install folium
Рис. 10. Хороплет-карта США по COVID-19 (folium). Два слоя на одной карте.
Построим карту по COVID-19 в США с двумя слоями: количество заболевших в каждом штате и летальность.
import folium
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
state_geo = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json"
covid_csv = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv"
state_data = pd.read_csv(covid_csv)
m = folium.Map(location=[48, -102], zoom_start=3)
folium.Choropleth(
geo_data=state_geo,
name="Подтвержденные случаи заражения",
data=state_data,
columns=["State", "Confirmed"],
key_on="feature.id",
fill_color="YlOrBr",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Подтвержденные случаи заражения",
).add_to(m)
print()
folium.Choropleth(
geo_data=state_geo,
name="Летальность",
data=state_data,
columns=["State", "Case_Fatality_Ratio"],
key_on="feature.id",
fill_color="Reds",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Летальность",
show = False,
).add_to(m)
folium.LayerControl().add_to(m)
m
Здесь:
folium.Choropleth – импорт модуля для построения карты.
columns – столбцы, которые используются для построения карты.
key – ключ, используемый для построения карты. По умолчанию id.
name – название карты.
fill_color – цвет из палитры ColorBrewer. Если данных в столбце нет (NaN), то цвет будет серый.
legend_name – описание под шкалой.
show – определяет, показывать ли слой при загрузке карты. По умолчанию значение True.
Рис. 11. Хороплет-карта США по COVID-19 (folium). Два слоя на одной карте.
Рис. 12. Интерактивная хороплет-карта США по COVID-19 (folium)
Сделаем так, чтобы при наведении курсора мыши на штат всплывало название штата:
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
state_geo = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json"
covid_csv = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv"
state_data = pd.read_csv(covid_csv)
m = folium.Map(location=[48, -102], zoom_start=3)
covid_map = folium.Choropleth(
geo_data=state_geo,
name="Подтвержденные случаи заражения",
data=state_data,
columns=["State", "Confirmed"],
key_on="feature.id",
fill_color="YlOrBr",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Подтвержденные случаи заражения",
).add_to(m)
folium.LayerControl().add_to(m)
covid_map.geojson.add_child(folium.features.GeoJsonTooltip(['name',], labels=False))
m
Здесь:
covid_map.geojson.add_child... – добавляет всплывающее окошко с названием штата.
Рис. 13. Две карты в одном окне (folium).
Создадим две карты в одном окне с помощью плагина DualMap. Для этого добавим к основной карте m дочерние карты m1 и m2 через запись m.m1 и m.m2 соответственно:
from folium import plugins
m = plugins.DualMap(location=(59.93863, 30.31413), tiles=None, zoom_start=11)
folium.TileLayer("openstreetmap").add_to(m)
folium.TileLayer("Stamen Terrain").add_to(m.m1)
folium.TileLayer("cartodbpositron").add_to(m.m2)
figure_both = folium.FeatureGroup(name="Метка на обеих картах").add_to(m)
figure_1 = folium.FeatureGroup(name="Метка слева").add_to(m.m1)
figure_2 = folium.FeatureGroup(name="Метка справа").add_to(m.m2)
icon_red = folium.Icon(color="green")
folium.Marker((59.93863, 30.31413), tooltip="Метка на обеих картах", icon=icon_red).add_to(figure_both)
folium.Marker((59.912563, 30.32413), tooltip="Метка слева").add_to(figure_1)
folium.Marker((59.93463, 30.38413), tooltip="Метка справа").add_to(figure_2)
folium.LayerControl(collapsed=False).add_to(m)
m
Здесь:
folium.TileLayer(" ") – добавляет на карту картографический слой. В нашем случае: openstreetmap, Stamen Terrain и cartodbpositron.
m.m1 и m.m2 – создает две карты: первая карта (слева) и вторая карта (справа).
.add_to(m), .add_to(m.m1), .add_to(m.m2) – добавляют маркеры на обе карты, только на первую карту и только на вторую соответственно.
Рис. 14. Группируем маркеры в (folium)
Создадим группы маркеров с возможностью включения и отключения их видимости:
m = folium.Map(location=[59.93863, 30.31413], zoom_start=12)
figure = folium.FeatureGroup(name="Все метки")
m.add_child(figure)
group1 = plugins.FeatureGroupSubGroup(figure, "Первая группа")
m.add_child(group1)
group2 = plugins.FeatureGroupSubGroup(figure, "Вторая группа")
m.add_child(group2)
folium.Marker([59.93863, 30.31413]).add_to(group1)
folium.Marker([59.95863, 30.31413]).add_to(group1)
folium.Marker([59.94863, 30.32513]).add_to(group2)
folium.Marker([59.91763, 30.31413]).add_to(group2)
folium.LayerControl(collapsed=False).add_to(m)
m
Здесь:
plugins.FeatureGroupSubGroup(figure, "name") – создает группы маркеров с именем name.
m.add_child(group1) – добавляет группы маркеров на карту.
folium.Marker([59.93863, 30.31413]).add_to(group1) – добавляет маркер в группу.
***
Мы проделали большую работу и познакомились с тремя географическими библиотеками: gmaps, ipyleaflet и folium. С их помощью научились:
Источник статьи: https://proglib.io/p/rabota-s-geodannymi-v-python-i-jupyter-2021-03-22
Рассмотрим три библиотеки по работе с геоданными: gmaps, ipyleaflet и более продвинутую по сравнению с предыдущими – folium. Забегая вперед, скажем, что лучше использовать folium, так как в ней удобнее строить интерактивные карты и работать со слоями. В конце статьи вы найдете ссылки на блокноты с кодом.
Установка Jupyter
Установим блокноты Jupyter следующей командой:pip install notebook
Запустим блокноты Jupyter:
jupyter notebook
Автоматически откроется страница по адресу http://localhost:8888/tree. Затем создадим новый блокнот, кликнув по кнопке New.
1. Библиотека gmaps
Начнем с простого – библиотеки gmaps. Для работы с ней нужен API-ключ. Как его получить читайте на сайте Google Maps Platform.Помимо gmaps нам понадобятся инструменты интерактивного управления ipywidgets, widgetsnbextension и библиотека для обработки и анализа данных pandas. Они устанавливаются как через консоль (pip install), так и прямо из блокнота через восклицательный знак (!pip install):
!pip install gmaps
!pip install pandas
!pip install widgetsnbextension
Активируем виджеты следующими командами:
!jupyter nbextension enable --py --sys-prefix widgetsnbextension
!jupyter nbextension enable --py --sys-prefix gmaps
1.1. Карта точек WiFi
За основу возьмем датасет, размещенный на портале открытых данных Москвы, в котором содержится информация о 2.8 тыс. бесплатных точек Wi-Fi. На каждой 1001-й строчке датасета дублируются названия столбцов. Во избежание ошибок при обработке набора данных, удалим эти строчки из таблицы. Очищенный массив доступен в репозитории на Гитхабе.
Какую информацию возьмем из датасета? Нам нужны координаты (Latitude_WGS84, Longitude_WGS84), адрес (Location) и количество точек доступа (NumberOfAccessPoints).
Cоздадим список wifi_points, состоящий из словарей, в каждом из которых хранится вышеперечисленная информация о каждой точке. Затем создадим отдельный список marker_coordinates с координатами и переведем элементы списка из типа строка str в тип вещественное число float, потому что координаты – это число, а не строчка.
wifi_gmaps.ipynb import pandas as pd
import gmaps
file_name = 'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/data-9776-2020-12-21.csv'
df = pd.read_csv(file_name, sep=';', encoding='cp1251')
gmaps.configure(api_key='...')
wifi_points = []
i = 0
while i < len(df.index):
wifi_points.append({'Coordinates': [df['Latitude_WGS84'], df['Longitude_WGS84']], 'Location': df['Location'], 'NumberOfAccessPoints': df['NumberOfAccessPoints']})
i += 1
marker_coordinates = [wifi['Coordinates'] for wifi in wifi_points]
marker_coordinates = [[float(x) for x in y] for y in marker_coordinates] # здесь мы проходимся по элементами вложенных списков и меняем их типы со str на float
info_box_template = """
<dl>
<dt>Адрес:</dt><dd>{Location}</dd>
<dt>Количество точек доступа:</dt><dd>{NumberOfAccessPoints}</dd>
</dl>
"""
marker_info = [info_box_template.format(**points) for points in wifi_points]
marker_layer = gmaps.marker_layer(marker_coordinates, info_box_content=marker_info )
fig = gmaps.figure()
fig.add_layer(marker_layer)
fig
Здесь:
sep – разделитель между столбцами.
encoding – кодировка файла.
info_box_template – формирует HTML-форму с описанием точки Wi-Fi.
<dl> – создает контейнер.
<dt> – заголовок.
<dd> – описание.
marker_info – список, содержащий форматированные строчки с описанием точек Wi-Fi: адрес точки (Location) и количество работающих точек Wi-Fi (NumberOfAccessPoints).
marker_layer – создает слой маркеров с соответствующими координатами.
fig = gmaps.figure() – инициирует создание карты.
fig.add_layer(marker_layer) – добавляет слой с маркерами на карту.
fig – запускает карту.
Ошибка Figure(layout)
Если при запуске блокнота выскочила ошибка Figure(layout=FigureLayout(height='420px')), то перезапустите блокнот, но не через панель управления блокнотом (Kernel → Restart), а через консоль.
2. Библиотека ipyleaflet
ipyleaflet – интерактивная библиотека виджетов, основанная ipywidgets. Библиотека использует карты OpenStreetMap.Установим библиотеки pandas, ipyleaflet и ipywidgets:
!pip install pandas
!pip install ipyleaflet
!pip install ipywidgets
2.1. Карта точек WiFi
Создадим карту с точками Wi-Fi, но уже с помощью библиотеки ipyleaflet. Воспользуемся датасетом из раздела про gmaps:
import pandas as pd
from ipywidgets import HTML
from ipyleaflet import Map, Marker, Popup
file_name = 'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/data-9776-2020-12-21.csv'
df = pd.read_csv(file_name, sep=';', encoding='cp1251')
wifi_points = []
i = 0
while i < len(df.index):
wifi_points.append({'index': i, 'Coordinates': [df['Latitude_WGS84'], df['Longitude_WGS84']], 'Location': df['Location'], 'NumberOfAccessPoints': df['NumberOfAccessPoints']})
i += 1
marker_coordinates = [wifi['Coordinates'] for wifi in wifi_points]
marker_coordinates = [[float(x) for x in y] for y in marker_coordinates]
m = Map(center=(55.753215, 37.622504), zoom=11)
markers = [Marker(location=(marker_coordinates)) for i in range(len(marker_coordinates))]
info_box_template = """
<dl>
<dt>Адрес:</dt><dd>{Location}</dd>
<dt>Количество точек доступа:</dt><dd>{NumberOfAccessPoints}</dd>
</dl>
"""
locations_info = [info_box_template.format(**point) for point in wifi_points]
for i in range(len(markers)):
markers.popup = HTML(locations_info)
m.add_layer(markers)
m
Здесь:
markers – список из координат маркеров.
locations_info – список из адресов и количества точек Wi-Fi.
for i in range(len(markers)) – каждый из элементов на карте представляет из себя слой, поэтому напишем цикл создающий нужное количество слоев. Один слой – один маркер.
m – отрисовывает карту с маркерами.
Ошибка: виджеты не отображаются
Если виджеты не отображаются, перезапустите блокноты Jupyter через консоль.
2.2. Маршрут марафона
Построим маршрут 5 км московского марафона: импортируем из библиотеки ipyleaflet модуль «Муравьиный путь» AntPath и добавим маркеры Старт и Финиш!.
from ipyleaflet import AntPath, WidgetControl
from ipywidgets import IntSlider, jslink
m = Map(center=(55.718148, 37.555493), zoom=13)
marathon_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(marathon_path)
start_marker = Marker(location=(55.717435, 37.561014))
m.add_layer(start_marker)
finish_marker = Marker(location=(55.720267, 37.5558))
m.add_layer(finish_marker)
start = HTML()
finish = HTML()
start.value = "Старт"
finish.value = "Финиш!"
start_marker.popup = start
finish_marker.popup = finish
zoom_slider = IntSlider(description='Масштаб:', min=11, max=15, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
marathon_path – координаты марафона.
start_marker и finish_marker – координаты маркеров Старт и Финиш! соответственно.
start.value и finish.value – описания маркеров старта и финиша, которые появятся во всплывающем окне при клике на маркер.
zoom_slider – ползунок масштаба.
color – цвет линии.
pulse_color – цвет бегущих муравьев.
2.3. Маршрут марафона с иконками AwesomeIcon
Заменим стандартные иконки маркеров на иконки из каталога AwesomeIcon:
from ipyleaflet import AwesomeIcon
m = Map(center=(55.718148, 37.555493), zoom=14)
marathon_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(marathon_path)
start_icon = AwesomeIcon(
name='fa-play',
marker_color='green',
icon_color='white'
)
start_marker = Marker(icon=start_icon, location=(55.717435, 37.561014))
start = HTML()
start.value = "Старт"
start_marker.popup = start
m.add_layer(start_marker)
finish_icon = AwesomeIcon(
name='fa-stop',
marker_color='blue',
icon_color='black'
)
finish_marker = Marker(icon=finish_icon, location=(55.720267, 37.5558))
finish = HTML()
finish.value = "Финиш!"
finish_marker.popup = finish
m.add_layer(finish_marker)
zoom_slider = IntSlider(description='Масштаб:', min=11, max=17, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
start_icon и finish_icon – содержат элементы из библиотеки AwesomeIcon.
marker_color – цвет маркера.
icon_color – цвет иконки.
2.4. Маршрут марафона с собственными иконками
Добавим собственные иконки с помощью модуля Icon:
from ipyleaflet import Icon
from ipywidgets import IntSlider
m = Map(center=(55.718148, 37.555493), zoom=14)
ant_path = AntPath(
locations=[
[55.717435, 37.561014], [55.712517, 37.569324], [55.712412, 37.569479],
[55.711333, 37.561858], [55.711344, 37.558516], [55.712049, 37.553513],
[55.713216, 37.550191], [55.71523, 37.54681], [55.717366, 37.544289],
[55.719874, 37.542966], [55.721958, 37.542939], [55.723928, 37.543701],
[55.725656, 37.545167], [55.7267, 37.546673], [55.727594, 37.54923],
[55.727481, 37.549349], [55.727053, 37.547923], [55.726619, 37.546807],
[55.724107, 37.549236], [55.723902, 37.549511], [55.720267, 37.5558]
],
dash_array=[1, 10],
delay=1000,
color='#9500ff',
pulse_color='#9500ff'
)
m.add_layer(ant_path)
start_icon = Icon(icon_url='https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/5d6126a97905792c584b1f9e18cd8dd767ba2966/start.png', icon_size=[97, 36])
start_marker = Marker(icon=start_icon, location=(55.717435, 37.561014))
start = HTML()
start.value = "Старт"
start_marker.popup = start
m.add_layer(start_marker)
finish_icon = Icon(icon_url='https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/5d6126a97905792c584b1f9e18cd8dd767ba2966/finish.png', icon_size=[97, 36])
finish_marker = Marker(icon=finish_icon, location=(55.720267, 37.5558))
finish = HTML()
finish.value = "Финиш!"
finish_marker.popup = finish
m.add_layer(finish_marker)
zoom_slider = IntSlider(description='Масштаб:', min=11, max=17, value=14)
jslink((zoom_slider, 'value'), (m, 'zoom'))
widget_control1 = WidgetControl(widget=zoom_slider, position='topright')
m.add_control(widget_control1)
m
Здесь:
Импортируем из библиотеки ipyleaflet модуль Icon, чтобы использовать собственные иконки.
icon_url– ссылка на иконку.
icon_size=[x, y] – задает размеры иконки: x – длина, y – высота.
2.5. Карта 85 субъектов РФ
Создадим карту с 85 субъектами РФ. Координаты границ субъектов возьмем из json-файла. Данные актуальны на 2015 год и в них есть дефект с Чукотским Автономным округом, но для нашей задачи – демонстрации возможностей библиотеки – этого вполне достаточно. Очищенная версия лежит в репозитории.
import os
import json
import random
import requests
from ipyleaflet import GeoJSON
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
m.add_layer(geo_json)
m
Здесь:
load_data – функция, которая записывает файл с данным в локальное хранилище.
random_color – функция, генерирующая случайные цвета для субъектов РФ.
style и hover_style – задают графическое отображение субъекта по умолчанию и при наведении на него курсора мыши.
2.6. Интерактивная карта РФ (по клику)
Сделаем карту интерактивной: при клике на субъект под картой появится название центрального города субъекта:
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
def handle_click(**kwargs):
print(kwargs['feature']['properties']['name'])
geo_json.on_click(handle_click)
m.add_layer(geo_json)
m
Здесь:
handle_click – функция, которая принимает именованные аргументы.
['name'] – имя субъекта.
geo_json.on_click(handle_click) – подключает к карте событие (вывод на экран) при клике на субъект.
2.7. Больше интерактива
Теперь, с помощью функции handle_hover сделаем так, чтобы название центрального города субъекта появлялось при наведении курсора мыши на субъект:
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/geo_ru.json',
'geo_ru.json',
json.load)
def random_color(feature):
return {
'color': 'black',
'fillColor': random.choice(['red', 'yellow', '#efed69', '#fcba03', '#9900ff', '#00ff15', '#db2751', '#00ff95']),
}
m = Map(center=(66.25, 94.15), zoom=3)
geo_json = GeoJSON(
data=data,
style={
'opacity': 1, 'dashArray': '9', 'fillOpacity': 0.2, 'weight': 1
},
hover_style={
'color': 'white', 'dashArray': '0', 'fillOpacity': 0.7
},
style_callback=random_color
)
def handle_hover(**kwargs):
print(kwargs['feature']['properties']['name'])
geo_json.on_hover(handle_hover)
m.add_layer(geo_json)
m
Здесь:
handle_hover – функция, принимающая именованные аргументы.
geo_json.on_click(handle_hover) – подключает к карте событие при наведении на субъект.
2.8. Хороплет-карта США по COVID-19
Построим хороплет-карту (фоновая картограмма) штатов США по COVID-19. На хороплет-карте цветом с различной степенью насыщенности отображается интенсивность какого-либо показателя. Данные по заболеваемости возьмем из репозитория университета Джона Хопкинса, а координаты границ штатов с сайта библиотеки ipyleaflet. Слегка изменим csv-файл, добавив в него второй столбец State с почтовыми сокращениями штатов США (Alabama – AL и так далее), чтобы была связь со вторым ключом (id) для каждого штата из json-файла. Также удалим несколько штатов из csv-файла, границы которых отсутствуют в json-файле.
import ipyleaflet
from ipywidgets import link, FloatSlider
from branca.colormap import linear
def load_data(url, filename, file_type):
r = requests.get(url)
with open(filename, 'w') as f:
f.write(r.content.decode("utf-8"))
with open(filename, 'r') as f:
return file_type(f)
geo_json_data = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json',
'us-states_covid.json',
json.load)
confirmed = load_data(
'https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv',
'03-13-2021_covid.csv',
pd.read_csv)
confirmed = dict(zip(confirmed['State'].tolist(), confirmed['Confirmed'].tolist()))
layer = ipyleaflet.Choropleth(
geo_data=geo_json_data,
choro_data=confirmed,
colormap=linear.YlOrRd_04,
border_color='black',
style={'fillOpacity': 0.8, 'dashArray': '5, 5'})
m = ipyleaflet.Map(center = (43,-100), zoom = 4)
m.add_layer(layer)
m
Здесь:
geo_json_data – загрузка json-файла с координатами границ штатов.
сonfirmed – загрузка csv-файла с данными по заболеваемости.
confirmed = dict... – создает словарь с ключем Почтовое название штата и значением Количество подтвержденных случаев заражения.
geo_data – координаты границ штатов.
choro_data – хороплет-данные, количество заболевших в каждом штате.
colormap – цвет из палитры ColorBrewer.
3. Библиотека folium
Теперь воспользуемся библиотекой folium, которая также работает на картах OpenStreetMap, но обладает большими возможностями по сравнению с ipyleaflet.3.1. Установка folium
Установим folium следующей командой:!pip install folium
3.2. Два слоя на одной карте
Построим карту по COVID-19 в США с двумя слоями: количество заболевших в каждом штате и летальность.
import folium
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
state_geo = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json"
covid_csv = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv"
state_data = pd.read_csv(covid_csv)
m = folium.Map(location=[48, -102], zoom_start=3)
folium.Choropleth(
geo_data=state_geo,
name="Подтвержденные случаи заражения",
data=state_data,
columns=["State", "Confirmed"],
key_on="feature.id",
fill_color="YlOrBr",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Подтвержденные случаи заражения",
).add_to(m)
print()
folium.Choropleth(
geo_data=state_geo,
name="Летальность",
data=state_data,
columns=["State", "Case_Fatality_Ratio"],
key_on="feature.id",
fill_color="Reds",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Летальность",
show = False,
).add_to(m)
folium.LayerControl().add_to(m)
m
Здесь:
folium.Choropleth – импорт модуля для построения карты.
columns – столбцы, которые используются для построения карты.
key – ключ, используемый для построения карты. По умолчанию id.
name – название карты.
fill_color – цвет из палитры ColorBrewer. Если данных в столбце нет (NaN), то цвет будет серый.
legend_name – описание под шкалой.
show – определяет, показывать ли слой при загрузке карты. По умолчанию значение True.
3.3. Добавляем интерактив: всплывающий текст
Сделаем так, чтобы при наведении курсора мыши на штат всплывало название штата:
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
state_geo = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/us-states_covid.json"
covid_csv = "https://raw.githubusercontent.com/tttdddnet/Python-Jupyter-Geo/main/03-13-2021_covid.csv"
state_data = pd.read_csv(covid_csv)
m = folium.Map(location=[48, -102], zoom_start=3)
covid_map = folium.Choropleth(
geo_data=state_geo,
name="Подтвержденные случаи заражения",
data=state_data,
columns=["State", "Confirmed"],
key_on="feature.id",
fill_color="YlOrBr",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Подтвержденные случаи заражения",
).add_to(m)
folium.LayerControl().add_to(m)
covid_map.geojson.add_child(folium.features.GeoJsonTooltip(['name',], labels=False))
m
Здесь:
covid_map.geojson.add_child... – добавляет всплывающее окошко с названием штата.
3.4. Две карты в одном окне
Создадим две карты в одном окне с помощью плагина DualMap. Для этого добавим к основной карте m дочерние карты m1 и m2 через запись m.m1 и m.m2 соответственно:
from folium import plugins
m = plugins.DualMap(location=(59.93863, 30.31413), tiles=None, zoom_start=11)
folium.TileLayer("openstreetmap").add_to(m)
folium.TileLayer("Stamen Terrain").add_to(m.m1)
folium.TileLayer("cartodbpositron").add_to(m.m2)
figure_both = folium.FeatureGroup(name="Метка на обеих картах").add_to(m)
figure_1 = folium.FeatureGroup(name="Метка слева").add_to(m.m1)
figure_2 = folium.FeatureGroup(name="Метка справа").add_to(m.m2)
icon_red = folium.Icon(color="green")
folium.Marker((59.93863, 30.31413), tooltip="Метка на обеих картах", icon=icon_red).add_to(figure_both)
folium.Marker((59.912563, 30.32413), tooltip="Метка слева").add_to(figure_1)
folium.Marker((59.93463, 30.38413), tooltip="Метка справа").add_to(figure_2)
folium.LayerControl(collapsed=False).add_to(m)
m
Здесь:
folium.TileLayer(" ") – добавляет на карту картографический слой. В нашем случае: openstreetmap, Stamen Terrain и cartodbpositron.
m.m1 и m.m2 – создает две карты: первая карта (слева) и вторая карта (справа).
.add_to(m), .add_to(m.m1), .add_to(m.m2) – добавляют маркеры на обе карты, только на первую карту и только на вторую соответственно.
3.5. Группируем маркеры
Создадим группы маркеров с возможностью включения и отключения их видимости:
m = folium.Map(location=[59.93863, 30.31413], zoom_start=12)
figure = folium.FeatureGroup(name="Все метки")
m.add_child(figure)
group1 = plugins.FeatureGroupSubGroup(figure, "Первая группа")
m.add_child(group1)
group2 = plugins.FeatureGroupSubGroup(figure, "Вторая группа")
m.add_child(group2)
folium.Marker([59.93863, 30.31413]).add_to(group1)
folium.Marker([59.95863, 30.31413]).add_to(group1)
folium.Marker([59.94863, 30.32513]).add_to(group2)
folium.Marker([59.91763, 30.31413]).add_to(group2)
folium.LayerControl(collapsed=False).add_to(m)
m
Здесь:
plugins.FeatureGroupSubGroup(figure, "name") – создает группы маркеров с именем name.
m.add_child(group1) – добавляет группы маркеров на карту.
folium.Marker([59.93863, 30.31413]).add_to(group1) – добавляет маркер в группу.
***
Мы проделали большую работу и познакомились с тремя географическими библиотеками: gmaps, ipyleaflet и folium. С их помощью научились:
- ставить на карту маркеры, группировать их и менять иконки маркеров на собственные;
- выделять на карте границы субъектов РФ и штатов США;
- рисовать хороплет-карты;
- создавать в одном окне две карты;
- читать json- и csv-файлы.
Источник статьи: https://proglib.io/p/rabota-s-geodannymi-v-python-i-jupyter-2021-03-22