Choropleth maps подсчет точек в области
Всем привет!
В Folium можно строить Choropleth связывая GeoJson и данные со значениями по ключам, но не нашёл информации можно ли построить такую карту имея только точки геокоординат + GeoJson. Таким образом получим тепловую карту которая показывать количество точек в областях. Возможно ли такое сделать?
Пример:
Буду благодарен за помощь!
Ответы (1 шт):
Это можно сделать, но сначала нужно подготовить данные для обработки. Придётся поточечно выяснять, входит ли каждая точка в полигон, чтобы засчитать ее - а это при больших объемах данных может занимать какое-то значимое время:
import folium
import pandas as pd
from shapely.geometry import Point, shape
import json
with open('Георайоны тестовые.json') as f:
myjson = json.load(f)
# Переводим json в формат geojson:
geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry" : {
"type": "Polygon",
"coordinates": d["coordinates"],
},
"properties" :
{
"id":idx
},
} for idx, d in enumerate(myjson["geometries"])]
}
# читаем файл с данными (я сохранил его из xls а csv для быстроты работы) в датафрейм
df = pd.read_csv("sample.csv")
# удаляем из датафрейма строки с отсутствиующими значениями:
df.dropna(inplace=True)
# создаем пустой словарь ля хранения значений количества точек в каждом полигоне:
values = {}
# с помощью модуля shapely проверяем, входят ли точки из датафрейма в наши полигоны.
# Если точка входит в полигон, то увеличиваем счетчик точек для этого полигона в словаре values
# ! ВНИМАНИЕ - здесь идёт построчный перебор датафрейма, эта процедура для больших датасетов может занимать много времени
for coord in df.itertuples():
point = Point(coord[4], coord[3])
for idx, feature in enumerate(geojson['features']):
polygon = shape(feature["geometry"])
if polygon.contains(point):
values.setdefault(idx,0)
values[idx]+=1
# создаем из словаря values датафрейм, с которым будет работать хороплет:
datum = pd.DataFrame.from_dict(values, orient="index").sort_index().reset_index()
datum.columns=["id", "values"]
# Инициируем базовую карту и центрируем ее по нашим полигонам (координаты получил опытным путём):
m = folium.Map(
location=[55.76, 37.61],
tiles="cartodbpositron",
zoom_start=10,
)
# отрисовываем на карте наши полигоны
folium.GeoJson(geojson, name="geojson").add_to(m)
# собственно, отрисовываем хороплет с нашими данными
choropleth = folium.Choropleth(
geo_data=geojson,
name="choropleth",
data=datum,
columns=["id", "values"],
key_on="feature.properties.id",
fill_color="YlGn",
fill_opacity=0.3,
line_opacity=0.1,
).add_to(m)
На выходе получаем такую вот "красоту":
UPDATE
я переделал код под конкретный случай автора вопроса: Генерация карты ввиду большого количества точек и полигонов занимает ЗНАЧИТЕЛЬНОЕ время.
import folium
import pandas as pd
from shapely.geometry import Point, shape
import json
m = folium.Map(
location=[55.66, 37.40],
tiles="cartodbpositron",
zoom_start=9,
)
folium.LatLngPopup().add_to(m)
with open('ao.geojson', encoding='utf-8') as f:
geojson = json.load(f)
folium.GeoJson(data=geojson, name="geojson").add_to(m)
df = pd.read_csv("sample.csv")
df.dropna(inplace=True)
values = {}
for i in range(0, len(geojson["features"])):
values[geojson["features"][i]["properties"]["NAME"]] = 0
# с помощью модуля shapely проверяем, входят ли точки из датафрейма в наши полигоны.
# Если точка входит в полигон, то увеличиваем счетчик точек для этого полигона в словаре values
# ! ВНИМАНИЕ - здесь идёт построчный перебор датафрейма, эта процедура для больших датасетов может занимать много времени
for coord in df.itertuples():
point = Point(coord[4], coord[3])
for i, feature in enumerate(geojson['features']):
polygon = shape(feature["geometry"])
if polygon.contains(point):
values[geojson["features"][i]["properties"]["NAME"]]+=1
# создаем из словаря values датафрейм, с которым будет работать хороплет:
datum = pd.DataFrame.from_dict(values, orient="index").sort_index().reset_index()
datum.columns=["id", "values"]
# собственно, отрисовываем хороплет с нашими данными
choropleth = folium.Choropleth(
geo_data=geojson,
name="choropleth",
data=datum,
columns=["id", "values"],
key_on="feature.properties.NAME",
fill_color="YlGn",
fill_opacity=0.3,
line_opacity=0.1,
).add_to(m)


