Опорные населенные пункты
[3]:
import warnings
import sys
import os
import requests
import geopandas as gpd
import pandas as pd
from popframe.models.region import Region
from popframe.method.anchor_settlement import AnchorSettlementBuilder
from typing import Dict, List, Optional, Union
import time
warnings.filterwarnings("ignore")
sys.stderr = open(os.devnull, 'w')
Проепроцессинг
Получение территорий
[2]:
def fetch_territories(
url='http://10.32.1.107:5300/api/v1/all_territories',
parent_id=1,
get_all_levels=False,
territory_type_id=None,
name=None,
cities_only=False,
created_at=None,
centers_only=False
):
params = {
'parent_id': parent_id,
'get_all_levels': get_all_levels,
'territory_type_id': territory_type_id,
'name': name,
'cities_only': cities_only,
'created_at': created_at,
'centers_only': centers_only
}
response = requests.get(url, params=params)
if response.status_code == 200:
geojson_data = response.json()
return gpd.GeoDataFrame.from_features(geojson_data['features']).set_crs(epsg=4326)
else:
print(f"Ошибка запроса: {response.status_code}")
return None
Данные по соц категориям
[3]:
BASE_URL = "http://10.32.1.47:5000/api"
CATEGORIES = ['soc_workers', 'soc_old', 'soc_parents']
METRICS = ['dev', 'soc', 'bas']
def get_region_data(territory_id: int) -> Optional[Dict]:
try:
response = requests.get(
f"{BASE_URL}/regions/values_identities",
params={'territory_id': int(territory_id)},
timeout=10
)
if response.status_code == 200:
return response.json()
return None
except (requests.exceptions.RequestException, ValueError):
return None
def fetch_unique_regions_data(territory_ids: List[int]) -> Dict[int, Dict]:
regions_data = {}
for territory_id in territory_ids:
data = get_region_data(territory_id)
regions_data[territory_id] = data
time.sleep(0.1) # Небольшая задержка между запросами
return regions_data
def enrich_geodataframe(
gdf: gpd.GeoDataFrame,
index: Optional[Union[int, List[int]]] = None,
suffix_format: str = '_{index}'
) -> gpd.GeoDataFrame:
# Определяем индексы для обработки
if index is None:
indices = [0, 1, 2]
elif isinstance(index, int):
indices = [index]
else:
indices = index
# Проверяем валидность индексов
if not all(0 <= i <= 2 for i in indices):
raise ValueError("Индексы должны быть в диапазоне [0, 2]")
# Получаем данные для уникальных parent_id
unique_parents = gdf['parent_id'].unique()
regions_data = fetch_unique_regions_data(unique_parents[~pd.isna(unique_parents)])
# Создаем новые колонки для каждой метрики
for category in CATEGORIES:
for metric in METRICS:
for i in indices:
suffix = suffix_format.format(index=i) if len(indices) > 1 else ''
column_name = f"{category}_{metric}{suffix}"
def safe_get_value(parent_id):
if pd.isna(parent_id):
return None
region_data = regions_data.get(parent_id)
if region_data is None:
return None
category_data = region_data.get(category)
if category_data is None:
return None
metric_data = category_data.get(metric)
if metric_data is None or i >= len(metric_data):
return None
return metric_data[i]
gdf[column_name] = gdf['parent_id'].apply(safe_get_value)
return gdf
def enrich_with_region_data(
gdf: gpd.GeoDataFrame,
index: Optional[Union[int, List[int]]] = None,
suffix_format: str = '_{index}'
) -> gpd.GeoDataFrame:
enriched_gdf = enrich_geodataframe(gdf, index, suffix_format)
return enriched_gdf
Функция поиска родительской территории по типу
[4]:
# Глобальный словарь для хранения информации о территориях
territory_dict = {}
def initialize_territory_dict(gdf: gpd.GeoDataFrame):
global territory_dict
territory_dict = {
row['id']: {
'level': row['level'],
'parent_id': row['parent']['id'] if pd.notna(row['parent']) else None,
'name': row['name'] # Добавляем name в словарь
}
for _, row in gdf.iterrows()
}
def find_parent_info(id: int, target_type_id: int) -> tuple:
if id not in territory_dict:
return None, None
current = territory_dict[id]
if not current['parent_id']:
return None, None
parent = territory_dict.get(current['parent_id'])
if parent and parent['level'] == target_type_id:
return current['parent_id'], parent['name']
return find_parent_info(current['parent_id'], target_type_id)
def find_parent_ids(target_gdf: gpd.GeoDataFrame,
reference_gdf: gpd.GeoDataFrame,
target_type_id: int) -> gpd.GeoDataFrame:
# Инициализируем словарь территорий на основе reference_gdf
initialize_territory_dict(reference_gdf)
# Применяем функцию поиска parent_id и name для каждой территории в target_gdf
parent_info = target_gdf['id'].apply(
lambda x: find_parent_info(x, target_type_id)
)
# Разделяем результаты на два столбца
target_gdf['parent_id'] = [info[0] if info else None for info in parent_info]
target_gdf['parent_name'] = [info[1] if info else None for info in parent_info]
return target_gdf
Получение данных из TownsNet
[5]:
API_URL = "http://10.32.1.102:5510/provision/{region_id}/get_evaluation"
CATEGORIES_PROV = ["Базовая", "Дополнительная", "Комфорт"]
CATEGORIES_COLUMNS = ['basic', 'additional', 'comfort']
def fetch_gdf(region_id: int, category_name: str, category_column: str):
params = {"category": category_name}
response = requests.get(API_URL.format(region_id=region_id), params=params)
if response.status_code == 200:
data = response.json()
gdf = gpd.GeoDataFrame.from_features(data["features"])
gdf = gdf[["geometry", category_column]]
return gdf
else:
raise Exception(f"API request failed with status {response.status_code}")
def fetch_all_categories(region_id: int):
gdfs = [fetch_gdf(region_id, name, category_column) for name, category_column in zip(CATEGORIES_PROV,CATEGORIES_COLUMNS)]
combined_gdf = gdfs[0]
for gdf, category in zip(gdfs[1:], CATEGORIES_COLUMNS[1:]):
combined_gdf = combined_gdf.merge(gdf[["geometry", category]], on="geometry", how="outer")
return combined_gdf
[6]:
def get_population(territories_gdf: gpd.GeoDataFrame):
POPULATION_COUNT_INDICATOR_ID =1
URBAN_API = 'http://10.32.1.107:5300'
res = requests.get(f'{URBAN_API}/api/v1/indicator/{POPULATION_COUNT_INDICATOR_ID}/values', verify=False)
res.raise_for_status()
res_df = pd.DataFrame(res.json())
res_df['territory_id'] = res_df['territory'].apply(lambda x: x['id'] if isinstance(x, dict) else None)
res_df = res_df[res_df['territory_id'].isin(territories_gdf['id'].values)]
res_df = (
res_df
.groupby('territory_id')
.agg({'value': 'last'})
.rename(columns={'value': 'population'})
)
territories_gdf = territories_gdf.merge(res_df, left_on='id', right_on='territory_id', how='left')
territories_gdf['population'] = territories_gdf['population'].fillna(0) # Заменяем NaN на 0
return territories_gdf
Получаем данные по городам и ГПСП
[7]:
all_territories = fetch_territories(parent_id=1, get_all_levels=True, cities_only=False, centers_only=True)
all_territories = all_territories.reset_index().rename(columns={'territory_id': 'id'})
all_territories
[7]:
| index | geometry | id | territory_type | parent | name | level | properties | admin_center | target_city_type | okato_code | oktmo_code | is_city | created_at | updated_at | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | POINT (34.61597 59.54053) | 2 | {'id': 2, 'name': 'Муниципальное образование'} | {'id': 1, 'name': 'Ленинградская область'} | Бокситогорский муниципальный район | 3 | {'Малые города': 2, 'Крупные города': 0, 'Числ... | {'id': 328, 'name': 'город Бокситогорск'} | None | 41203000000 | 41603000 | False | 2024-06-16T21:35:40.801621Z | 2024-11-14T12:17:18.795643Z |
| 1 | 1 | POINT (34.28178 59.4324) | 3 | {'id': 3, 'name': 'Поселение'} | {'id': 2, 'name': 'Бокситогорский муниципальны... | Самойловское сельское поселение | 4 | {'Численность населения': 2154, 'Административ... | {'id': 310, 'name': 'поселок Совхозный'} | None | 41203876000 | 41603476 | False | 2024-06-16T21:35:40.801621Z | 2024-11-14T12:17:52.703740Z |
| 2 | 2 | POINT (33.95669 59.66792) | 4 | {'id': 3, 'name': 'Поселение'} | {'id': 2, 'name': 'Бокситогорский муниципальны... | Большедворское сельское поселение | 4 | {'Численность населения': 1698, 'Административ... | {'id': 427, 'name': 'деревня Большой Двор'} | None | 41203812000 | 41603412 | False | 2024-06-16T21:35:40.801621Z | 2024-11-14T12:17:34.396287Z |
| 3 | 3 | POINT (34.14548 59.52005) | 5 | {'id': 3, 'name': 'Поселение'} | {'id': 2, 'name': 'Бокситогорский муниципальны... | Пикалевское городское поселение | 4 | {'Численность населения': 20169, 'Администрати... | {'id': 335, 'name': 'город Пикалево'} | None | 41440000000 | 41603102 | False | 2024-06-16T21:35:40.801621Z | 2024-11-14T12:17:34.930089Z |
| 4 | 4 | POINT (33.85846 59.34944) | 6 | {'id': 3, 'name': 'Поселение'} | {'id': 2, 'name': 'Бокситогорский муниципальны... | Борское сельское поселение | 4 | {'Численность населения': 3393, 'Административ... | {'id': 2859, 'name': 'деревня Бор'} | None | 41203816000 | 41603416 | False | 2024-06-16T21:35:40.801621Z | 2024-11-14T12:17:35.367513Z |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3131 | 3131 | POINT (31.2342 59.17022) | 3133 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Апраксин Бор | 5 | {} | None | None | 41248844010 | 41648444111 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:24.081332Z |
| 3132 | 3132 | POINT (31.32183 59.18624) | 3134 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Александровка | 5 | {} | None | None | 41248844002 | 41648444106 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T11:14:58.578700Z |
| 3133 | 3133 | POINT (31.48353 59.28739) | 3135 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Большая Горка | 5 | {} | None | None | 41248860002 | 41648444131 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:27.219027Z |
| 3134 | 3134 | POINT (31.45352 59.30929) | 3136 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Дроздово | 5 | {} | None | None | 41248860003 | 41648444146 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:27.140158Z |
| 3135 | 3135 | POINT (31.4571 59.30223) | 3137 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Большая Кунесть | 5 | {} | None | None | 41248860009 | 41648444136 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T11:29:40.547203Z |
3136 rows × 15 columns
[8]:
# all_territories.to_parquet('data/all_territories.parquet')
# all_territories = gpd.read_parquet('data/all_territories.parquet')
Данные сохранены в файлы, при необходимиости можно раскомментировать код и получить обновленные данные
[9]:
# Получение данных о городах
towns_gdf = fetch_territories(parent_id=1, get_all_levels=True, cities_only=True, centers_only=True)
towns_gdf
[9]:
| geometry | territory_id | territory_type | parent | name | level | properties | admin_center | target_city_type | okato_code | oktmo_code | is_city | created_at | updated_at | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | POINT (33.74561 59.36031) | 207 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 6, 'name': 'Борское сельское поселение'} | деревня Болото | 5 | {} | None | None | 41203816004 | 41603416106 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:49.047689Z |
| 1 | POINT (33.78685 59.47791) | 208 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 6, 'name': 'Борское сельское поселение'} | деревня Большой Остров | 5 | {} | None | None | 41203816020 | 41603416111 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:50.317027Z |
| 2 | POINT (33.79438 59.47479) | 209 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 6, 'name': 'Борское сельское поселение'} | деревня Бор | 5 | {} | None | None | 41203816001 | 41603416101 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T11:08:10.553286Z |
| 3 | POINT (33.77497 59.44313) | 210 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 6, 'name': 'Борское сельское поселение'} | деревня Бороватое | 5 | {} | None | None | 41203816005 | 41603416116 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:50.270215Z |
| 4 | POINT (33.67886 59.33333) | 211 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 6, 'name': 'Борское сельское поселение'} | деревня Бочево | 5 | {} | None | None | 41203816003 | 41603416121 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T10:15:56.823065Z |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2926 | POINT (31.2342 59.17022) | 3133 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Апраксин Бор | 5 | {} | None | None | 41248844010 | 41648444111 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:24.081332Z |
| 2927 | POINT (31.32183 59.18624) | 3134 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Александровка | 5 | {} | None | None | 41248844002 | 41648444106 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T11:14:58.578700Z |
| 2928 | POINT (31.48353 59.28739) | 3135 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Большая Горка | 5 | {} | None | None | 41248860002 | 41648444131 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:27.219027Z |
| 2929 | POINT (31.45352 59.30929) | 3136 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Дроздово | 5 | {} | None | None | 41248860003 | 41648444146 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T21:46:27.140158Z |
| 2930 | POINT (31.4571 59.30223) | 3137 | {'id': 18, 'name': 'Населенный пункт'} | {'id': 205, 'name': 'Трубникоборское сельское ... | деревня Большая Кунесть | 5 | {} | None | None | 41248860009 | 41648444136 | True | 2024-06-16T21:35:40.801621Z | 2025-05-22T11:29:40.547203Z |
2931 rows × 14 columns
[10]:
towns_gdf['is_anchor_settlement'] = towns_gdf['target_city_type'].apply(lambda x: x is not None and 'id' in x)
towns_gdf["is_anchor_settlement"] = towns_gdf["is_anchor_settlement"].astype(bool)
towns_gdf = towns_gdf[['geometry', 'territory_id', 'name', 'is_anchor_settlement']]
towns_gdf = towns_gdf.reset_index().rename(columns={'territory_id': 'id'})
towns_gdf
[10]:
| index | geometry | id | name | is_anchor_settlement | |
|---|---|---|---|---|---|
| 0 | 0 | POINT (33.74561 59.36031) | 207 | деревня Болото | False |
| 1 | 1 | POINT (33.78685 59.47791) | 208 | деревня Большой Остров | False |
| 2 | 2 | POINT (33.79438 59.47479) | 209 | деревня Бор | False |
| 3 | 3 | POINT (33.77497 59.44313) | 210 | деревня Бороватое | False |
| 4 | 4 | POINT (33.67886 59.33333) | 211 | деревня Бочево | False |
| ... | ... | ... | ... | ... | ... |
| 2926 | 2926 | POINT (31.2342 59.17022) | 3133 | деревня Апраксин Бор | False |
| 2927 | 2927 | POINT (31.32183 59.18624) | 3134 | деревня Александровка | False |
| 2928 | 2928 | POINT (31.48353 59.28739) | 3135 | деревня Большая Горка | False |
| 2929 | 2929 | POINT (31.45352 59.30929) | 3136 | деревня Дроздово | False |
| 2930 | 2930 | POINT (31.4571 59.30223) | 3137 | деревня Большая Кунесть | False |
2931 rows × 5 columns
[11]:
towns_gdf = find_parent_ids(towns_gdf, all_territories, target_type_id=4)
towns_gdf
[11]:
| index | geometry | id | name | is_anchor_settlement | parent_id | parent_name | |
|---|---|---|---|---|---|---|---|
| 0 | 0 | POINT (33.74561 59.36031) | 207 | деревня Болото | False | 6.0 | Борское сельское поселение |
| 1 | 1 | POINT (33.78685 59.47791) | 208 | деревня Большой Остров | False | 6.0 | Борское сельское поселение |
| 2 | 2 | POINT (33.79438 59.47479) | 209 | деревня Бор | False | 6.0 | Борское сельское поселение |
| 3 | 3 | POINT (33.77497 59.44313) | 210 | деревня Бороватое | False | 6.0 | Борское сельское поселение |
| 4 | 4 | POINT (33.67886 59.33333) | 211 | деревня Бочево | False | 6.0 | Борское сельское поселение |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 2926 | 2926 | POINT (31.2342 59.17022) | 3133 | деревня Апраксин Бор | False | 205.0 | Трубникоборское сельское поселение |
| 2927 | 2927 | POINT (31.32183 59.18624) | 3134 | деревня Александровка | False | 205.0 | Трубникоборское сельское поселение |
| 2928 | 2928 | POINT (31.48353 59.28739) | 3135 | деревня Большая Горка | False | 205.0 | Трубникоборское сельское поселение |
| 2929 | 2929 | POINT (31.45352 59.30929) | 3136 | деревня Дроздово | False | 205.0 | Трубникоборское сельское поселение |
| 2930 | 2930 | POINT (31.4571 59.30223) | 3137 | деревня Большая Кунесть | False | 205.0 | Трубникоборское сельское поселение |
2931 rows × 7 columns
[13]:
towns_gdf = enrich_with_region_data(towns_gdf, index=0)
towns_gdf
[13]:
| index | geometry | id | name | is_anchor_settlement | parent_id | parent_name | population | soc_workers_dev | soc_workers_soc | soc_workers_bas | soc_old_dev | soc_old_soc | soc_old_bas | soc_parents_dev | soc_parents_soc | soc_parents_bas | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | POINT (33.74561 59.36031) | 207 | деревня Болото | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | 0.096542 | 0.194644 | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 |
| 1 | 1 | POINT (33.78685 59.47791) | 208 | деревня Большой Остров | False | 6.0 | Борское сельское поселение | 68.0 | None | 0.033795 | 0.096542 | 0.194644 | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 |
| 2 | 2 | POINT (33.79438 59.47479) | 209 | деревня Бор | False | 6.0 | Борское сельское поселение | 1734.0 | None | 0.033795 | 0.096542 | 0.194644 | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 |
| 3 | 3 | POINT (33.77497 59.44313) | 210 | деревня Бороватое | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | 0.096542 | 0.194644 | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 |
| 4 | 4 | POINT (33.67886 59.33333) | 211 | деревня Бочево | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | 0.096542 | 0.194644 | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2926 | 2926 | POINT (31.2342 59.17022) | 3133 | деревня Апраксин Бор | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | 0.520615 | 0.271781 | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 |
| 2927 | 2927 | POINT (31.32183 59.18624) | 3134 | деревня Александровка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | 0.520615 | 0.271781 | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 |
| 2928 | 2928 | POINT (31.48353 59.28739) | 3135 | деревня Большая Горка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | 0.520615 | 0.271781 | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 |
| 2929 | 2929 | POINT (31.45352 59.30929) | 3136 | деревня Дроздово | False | 205.0 | Трубникоборское сельское поселение | 5.0 | None | 0.152398 | 0.520615 | 0.271781 | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 |
| 2930 | 2930 | POINT (31.4571 59.30223) | 3137 | деревня Большая Кунесть | False | 205.0 | Трубникоборское сельское поселение | 5.0 | None | 0.152398 | 0.520615 | 0.271781 | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 |
2931 rows × 17 columns
[14]:
provision_gdf = fetch_all_categories(1)
provision_gdf = provision_gdf.set_crs(epsg=4326)
# Добавляем буфер вокруг точек в gdf1
orig_geometry = towns_gdf['geometry']
towns_gdf['geometry'] = towns_gdf.geometry.buffer(0.002)
towns_gdf = towns_gdf.sjoin(provision_gdf, how='left', predicate='intersects')
towns_gdf['geometry'] = orig_geometry
towns_gdf['provision'] = towns_gdf[['basic', 'additional', 'comfort']].mean(axis=1)
# towns_gdf.to_parquet('data/towns_gdf.parquet')
towns_gdf
[14]:
| index | geometry | id | name | is_anchor_settlement | parent_id | parent_name | population | soc_workers_dev | soc_workers_soc | ... | soc_old_soc | soc_old_bas | soc_parents_dev | soc_parents_soc | soc_parents_bas | index_right | basic | additional | comfort | provision | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | POINT (33.74561 59.36031) | 207 | деревня Болото | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | NaN | NaN | NaN | NaN | NaN |
| 1 | 1 | POINT (33.78685 59.47791) | 208 | деревня Большой Остров | False | 6.0 | Борское сельское поселение | 68.0 | None | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | NaN | NaN | NaN | NaN | NaN |
| 2 | 2 | POINT (33.79438 59.47479) | 209 | деревня Бор | False | 6.0 | Борское сельское поселение | 1734.0 | None | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | NaN | NaN | NaN | NaN | NaN |
| 3 | 3 | POINT (33.77497 59.44313) | 210 | деревня Бороватое | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 3.0 | 0.53 | 0.7 | 0.4 | 0.543333 |
| 4 | 4 | POINT (33.67886 59.33333) | 211 | деревня Бочево | False | 6.0 | Борское сельское поселение | 10.0 | None | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | NaN | NaN | NaN | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2926 | 2926 | POINT (31.2342 59.17022) | 3133 | деревня Апраксин Бор | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 2926.0 | 0.20 | 0.4 | 0.2 | 0.266667 |
| 2927 | 2927 | POINT (31.32183 59.18624) | 3134 | деревня Александровка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | NaN | NaN | NaN | NaN | NaN |
| 2928 | 2928 | POINT (31.48353 59.28739) | 3135 | деревня Большая Горка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | None | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | NaN | NaN | NaN | NaN | NaN |
| 2929 | 2929 | POINT (31.45352 59.30929) | 3136 | деревня Дроздово | False | 205.0 | Трубникоборское сельское поселение | 5.0 | None | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | NaN | NaN | NaN | NaN | NaN |
| 2930 | 2930 | POINT (31.4571 59.30223) | 3137 | деревня Большая Кунесть | False | 205.0 | Трубникоборское сельское поселение | 5.0 | None | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 2930.0 | 0.33 | 0.4 | 0.4 | 0.376667 |
2932 rows × 22 columns
[15]:
# towns_gdf = gpd.read_parquet('data/cities_gdf.parquet')
# towns_gdf['provision'] = towns_gdf[['basic', 'additional', 'comfort']].mean(axis=1)
towns_gdf = towns_gdf.set_index("id", drop=False)
towns_gdf = towns_gdf.fillna(0)
towns_gdf = towns_gdf.to_crs(4326)
towns_gdf['parent_name'] = towns_gdf['parent_name'].fillna('').astype(str)
# теперь можно безопасно сохранить в parquet
towns_gdf.to_parquet('data/towns_gdf.parquet')
towns_gdf
[15]:
| index | geometry | id | name | is_anchor_settlement | parent_id | parent_name | population | soc_workers_dev | soc_workers_soc | ... | soc_old_soc | soc_old_bas | soc_parents_dev | soc_parents_soc | soc_parents_bas | index_right | basic | additional | comfort | provision | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||||||||
| 207 | 0 | POINT (33.74561 59.36031) | 207 | деревня Болото | False | 6.0 | Борское сельское поселение | 10.0 | 0 | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 208 | 1 | POINT (33.78685 59.47791) | 208 | деревня Большой Остров | False | 6.0 | Борское сельское поселение | 68.0 | 0 | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 209 | 2 | POINT (33.79438 59.47479) | 209 | деревня Бор | False | 6.0 | Борское сельское поселение | 1734.0 | 0 | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 210 | 3 | POINT (33.77497 59.44313) | 210 | деревня Бороватое | False | 6.0 | Борское сельское поселение | 10.0 | 0 | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 3.0 | 0.53 | 0.7 | 0.4 | 0.543333 |
| 211 | 4 | POINT (33.67886 59.33333) | 211 | деревня Бочево | False | 6.0 | Борское сельское поселение | 10.0 | 0 | 0.033795 | ... | 0.041469 | 0.072120 | 0.308008 | 0.033795 | 0.002834 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3133 | 2926 | POINT (31.2342 59.17022) | 3133 | деревня Апраксин Бор | False | 205.0 | Трубникоборское сельское поселение | 313.0 | 0 | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 2926.0 | 0.20 | 0.4 | 0.2 | 0.266667 |
| 3134 | 2927 | POINT (31.32183 59.18624) | 3134 | деревня Александровка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | 0 | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 3135 | 2928 | POINT (31.48353 59.28739) | 3135 | деревня Большая Горка | False | 205.0 | Трубникоборское сельское поселение | 313.0 | 0 | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 3136 | 2929 | POINT (31.45352 59.30929) | 3136 | деревня Дроздово | False | 205.0 | Трубникоборское сельское поселение | 5.0 | 0 | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 0.0 | 0.00 | 0.0 | 0.0 | 0.000000 |
| 3137 | 2930 | POINT (31.4571 59.30223) | 3137 | деревня Большая Кунесть | False | 205.0 | Трубникоборское сельское поселение | 5.0 | 0 | 0.152398 | ... | 0.105424 | 0.491682 | 0.335392 | 0.152398 | 0.226743 | 2930.0 | 0.33 | 0.4 | 0.4 | 0.376667 |
2932 rows × 22 columns
Работа метода
Границы опорных пунктов
[4]:
from popframe.models.region import Region
from popframe.method.anchor_settlement import AnchorSettlementBuilder
# Создаем экземпляр класса
region_model = Region.from_pickle('data/1.pickle')
builder = AnchorSettlementBuilder(region=region_model)
# Вызываем метод построения границ
towns_gdf = gpd.read_parquet('data/towns_gdf.parquet')
settlement_boundaries = builder.get_anchor_settlement_boundaries(towns_gdf, time = 50)
[ ]:
# settlement_boundaries.to_file('data/settlement_boundaries.geojson', driver='GeoJSON')
[5]:
import matplotlib.pyplot as plt
import geopandas as gpd
# Создание графика и оси
fig, ax = plt.subplots(figsize=(30, 10))
# Визуализация границ с заливкой светло-голубым цветом
settlement_boundaries.plot(ax=ax, edgecolor="black", facecolor="#ADD8E6", linewidth=1)
# Визуализация границ региона (серым цветом с прозрачностью)
region_boundary = region_model.region
region_boundary.plot(ax=ax, color='gray', edgecolor='black', alpha=0.3)
local_crs = region_boundary.crs
non_anchor_towns = towns_gdf[towns_gdf["is_anchor_settlement"] == False] # Не опорные города
anchor_towns = towns_gdf[towns_gdf["is_anchor_settlement"] == True] # Не опорные города
non_anchor_towns = non_anchor_towns.to_crs(local_crs)
anchor_towns = anchor_towns.to_crs(local_crs)
# Визуализация не опорных городов (тепловая карта по provision)
non_anchor_towns.plot(
ax=ax,
column="basic", # Градиент по 'provision'
cmap="YlOrRd", # От жёлтого к красному
legend=True, # Включаем легенду
markersize=non_anchor_towns["basic"] * 10, # Размер точек по значению
alpha=0.7
)
# Визуализация опорных городов (зелёным цветом)
anchor_towns.plot(
ax=ax,
color="green", # Фиксированный зелёный цвет
markersize=50, # Размер маркеров
alpha=0.9,
edgecolor="black"
)
# Настройки отображения
ax.set_axis_off()
# Показ графика
plt.show()