Choropleth maps подсчет точек в области

Всем привет!

В Folium можно строить Choropleth связывая GeoJson и данные со значениями по ключам, но не нашёл информации можно ли построить такую карту имея только точки геокоординат + GeoJson. Таким образом получим тепловую карту которая показывать количество точек в областях. Возможно ли такое сделать?

Пример:

введите сюда описание изображения

Буду благодарен за помощь!


Ответы (1 шт):

Автор решения: strawdog

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

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)    

введите сюда описание изображения

→ Ссылка