<jupyter_start><jupyter_text>Открытый курс по машинному обучениюАвтор материала: <NAME> (@shlur), DS в Lamoda.  Рисуем интерактивные карты с Folium В питоне есть множество библиотек, с помощью которых можно рисовать и анализировать пространственную информацию (spatial analysis).Вот некоторые из них:* folium* gmaps* basemap* cartopy* geoplotlibВ этом туториале пойдет речь о библиотеке Folium (https://github.com/python-visualization/folium), которая представляет собой питон-обертку над JS библиотекой Leaflet."Manipulate your data in Python, then visualize it in on a Leaflet map via Folium." (c) githubБольшим плюсом по сравнению с другими библиотеками является интерактивность. Карты можно зумить, исследовать, кликать на маркеры, создать сложные типы визуализации.Минусом является производительность. Создание карты с большим количеством точек может составлять минуты.К сожалению, информация по работе с библиотекой раскидана по разным сайтам и туториалам. В официальной документации информации очень мало, а в русскоязычном интернете вообще ничего нет.Будем исследовать датасет с пабами Москвы =). Датасет в виде списка пабов Москвы с их координатами выгружен с http://openstreetmap.ru  Подготовка данных<jupyter_code>import json

import folium
import pandas as pd
import requests

with open('../../data/pubs.json') as json_data:
    d = json.load(json_data)
    
columns = ['lat', 'lon', 'name_ru', 'opening_hours', 'website']
index = range(0, len(d["data"]))
pubs = pd.DataFrame(columns = columns, index = index)

for i in range(0, len(d["data"])):
    pubs['lat'][i] = d["data"][i]["lat"]
    pubs['lon'][i] = d["data"][i]["lon"]
    pubs['opening_hours'].iloc[i] = d["data"][i]["opening_hours"]
    pubs['website'][i] = d["data"][i]["website"]
    pubs['name_ru'][i] = d["data"][i]["name_ru"]    
pubs.head(3)
# Для центрирования карт я выбрала центральную точку Москвы

kremlin = [55.750730, 37.617322]<jupyter_output><empty_output><jupyter_text>Dot density map Самый простой вариант анализа - отобразить данные как точки (или маркеры) на карте. В popup (выноску) положим название заведения и часы работы.Карта инициализируется с помощью синтаксиса `map = folium.Map(location=kremlin, zoom_start=11)`.Добавляем маркеры `folium.Marker().add_to(map)`.Различные типы маркеров задаются функциями:- Marker (использую для визуализации ниже)- RegularPolygonMarker- CircleMarker- PolygonMarkerВозможные атрибуты: - color- fill_color- weight- radius- number_of_sides (для RegularPolygonMarker)Так же в выноску можно передавать график vincent (https://github.com/wrobstory/vincent) с помощью синтаксиса: `folium.Popup().add_child(folium.Vega())``tiles` - источник тайлов карт. Я обычно использую openstreetmaps - они идут по умолчанию.<jupyter_code>pubs_map = folium.Map(location=kremlin, zoom_start=11)

for i in range(0, len(pubs)):
    folium.Marker([pubs['lat'][i], pubs['lon'][i]], popup = str(pubs['name_ru'][i]) + ": " 
                  + str(pubs['opening_hours'][i])).add_to(pubs_map)
    
pubs_map<jupyter_output><empty_output><jupyter_text>Cluster marker - раскраска в зависимости от плотности точек. Близкие точки сливаются в один маркер.Судя по данным, наибольшая плотность пабов в Москве - на серево-востоке от Кремля, в районе Чистых прудов.<jupyter_code>from folium import features

pubs_map = folium.Map(location=kremlin, zoom_start=12)
mc = features.MarkerCluster()

for i in range(0, len(pubs)):
    mk = features.Marker([pubs['lat'][i], pubs['lon'][i]])
    mc.add_child(mk)
    
pubs_map.add_child(mc)<jupyter_output><empty_output><jupyter_text>Heatmap Построим Heatmap распределения пабов по Москве<jupyter_code>import random

import numpy as np
from folium import plugins

pubs_map = folium.Map(location=kremlin, zoom_start=10)

data = [[x[0], x[1], 1] for x in np.array(pubs[['lat', 'lon']])]

HeatMap(data, radius = 20).add_to(pubs_map)
pubs_map<jupyter_output><empty_output><jupyter_text>Линии Добавим на карту линии, соединяющую локации. Она создаётся с помощью folium.PolyLine, который принимает координаты соединяемых точек, и настраивается параметрами, схожими с параметрами маркеров.Здесь мы выбрали и соединили 4 заведения в Сокольниках:<jupyter_code>sololniki = [55.791981, 37.664456]

pubs_map_sokolniki = folium.Map(location=sololniki, zoom_start=13)
path  = []
for i in [100, 101, 102, 103]:
    folium.Marker([pubs['lat'][i], pubs['lon'][i]], popup = str(pubs['name_ru'][i]) + ": " 
                  + str(pubs['opening_hours'][i])).add_to(pubs_map_sokolniki)
    path.append([[pubs['lat'][i], pubs['lon'][i]], [pubs['lat'][i+1], pubs['lon'][i+1]]])

folium.PolyLine(path[0:3], color='blue', weight=4, opacity=0.7, popup=str(i)).add_to(pubs_map_sokolniki)
pubs_map_sokolniki<jupyter_output><empty_output><jupyter_text>Найдем и отобразим кратчайший путь через пабы Москвы :) В заключении туториала, приведу пример отображения кратчайшего пути через пабы Москвы. Идея нагло украдена отсюда: http://www.math.uwaterloo.ca/tsp/pubs/Для нахождения кратчайшего пути использую библиотеку Google or-tools, которая включает в себя алгоритмы решения задач нахождения маршрута. Работа с ней это тема для отдельного туториала, поэтому загружаю найденное решение из внешнего файла.Пути между заведениями тут уже строятся не отрезками, соединяющими пары пабов, а следуют кратчайшему маршруту из паба в паб, подобранному с помощью http://project-osrm.org<jupyter_code>import pickle

# инициализируем карту
map = folium.Map(location=kremlin, zoom_start=14)

# грузим файл с данными о маршрутах
file = open('../../data/tutorial_data.pickle', 'rb')
routes = pickle.load(file,encoding='latin1')
file.close()

# Рисуем большой полилайн полного маршрута...
for path in routes['paths']:
    folium.PolyLine(path, color='black', weight=3, opacity=0.8).add_to(map)
# ...и маркеры пабов
for point in routes['points']:
    folium.Marker(point).add_to(map)

map<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11991869918699187, 'fraction_numerical': 0.013211382113821139, 'mean_word_length': 5.93075117370892, 'pattern_counts': {'":': 2, '<': 26, '<?xml version=': 0, '>': 26, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '148851', 'license': 'Unlicense', 'n_tokens_mistral': 2425, 'n_tokens_neox': 2655, 'n_words': 542, 'path': 'jupyter_russian/tutorials/folium_shlur.ipynb', 'repo_name': 'salman394/AI-ml--course', 'size': '5918'}