Indicators calculation

[25]:
import geopandas as gpd
from transport_frames.indicators import *

import os
os.getcwd()

import pickle

Initialization

[26]:
local_crs = 32637 # Tula region crs

The region road network graph can be obtained via transport_frames.graph.get_graph()

[27]:
with open("data/G_drive.pickle", "rb") as f:
    G_drive = pickle.load(f)

Area indicators

Requires the settlement_points - points of interest to calculate distances from.

distrcits_polygons - the polygons for data aggregation on different levels. Can be used for regional, district and settlement levels.

[28]:
districts_polygons = gpd.read_file("data/tula_region_districts.geojson")
settlement_points = gpd.read_file("data/tula_region_towns.geojson")

Distance (in km) to administrative center of the region.

[29]:
region_admin_center =ox.geocode_to_gdf("N34389350",by_osmid=True) # get head town of Tula region by osmid

get_distance_to_region_admin_center(region_admin_center,settlement_points,districts_polygons,G_drive).head()
2026-04-04 23:07:28.476 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[29]:
name geometry distance_to_admin_center
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 116.5165
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 130.6290
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 81.9230
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 65.4200
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 110.3645

Distance (in km) to federal roads.

[30]:
get_distance_to_federal_roads(settlement_points,districts_polygons,G_drive).head()
2026-04-04 23:07:30.560 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[30]:
name geometry distance_to_federal_roads
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 38.1005
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 87.5390
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 21.7050
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 6.6210
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 15.7180

Length of the roads in km for every district.

[31]:
get_road_length(G_drive, districts_polygons).head()
[31]:
name geometry road_length
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 785.737024
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 1214.120013
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 1078.153011
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 1752.549471
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 1062.859612

Density of the roads \(\mathrm{km/km^2}\).

[32]:
get_road_density(G_drive,districts_polygons).head()
[32]:
name geometry density
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 0.735164
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 1.022344
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 1.124087
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 1.077431
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 0.989979

Length of roads for each reg status (1 - federal, 2 - regional, 3 - local).

[33]:
get_reg_length(G_drive,districts_polygons).head()
[33]:
name geometry length_reg_1 length_reg_2 length_reg_3
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 0.000000 82.519950 703.217074
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 0.000000 170.932641 1043.187372
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 28.650916 183.168970 866.333125
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 148.987997 129.857315 1473.704159
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 56.833476 40.031030 965.995106

Connectivity of territories in minutes (median accessibility) based on road network graph.

[34]:
drive_connectivity = get_connectivity(settlement_points=settlement_points,
                       area_polygons=districts_polygons,
                       local_crs=local_crs,
                       graph=G_drive)
drive_connectivity.head()
2026-04-04 23:07:37.203 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[34]:
name geometry connectivity
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 137.141621
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 158.219155
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 102.153146
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 104.694100
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 111.845791
[35]:
import pandas as pd
import matplotlib.pyplot as plt


fig, ax = plt.subplots(figsize=(10, 8))
drive_connectivity.plot(
    column="connectivity",
    cmap="RdYlGn_r",
    legend=True,
    linewidth=0.2,
    edgecolor="white",
    ax=ax,
)

ax.set_axis_off()
ax.set_title("Drive connectivity in minutes")
plt.tight_layout()
../_images/examples_2_indicators_21_0.png

Connectivity of territories in minutes based on intermodal network graph (public transport + walk paths).

Intermodal transport graph can be obtained using transport_frames.graph.get_intermodal_graph

[36]:
with open("data/G_inter.pickle", "rb") as f:
    G_pt = pickle.load(f)

intermodal_connectivity = get_connectivity(settlement_points=settlement_points,
                       area_polygons=districts_polygons,
                       local_crs=local_crs,
                       graph=G_pt)
intermodal_connectivity.head()
[36]:
name geometry connectivity
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 1379.251669
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 1604.354486
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 907.622067
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 1105.028943
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 1103.344816
[37]:
fig, ax = plt.subplots(figsize=(10, 8))
intermodal_connectivity.plot(
    column="connectivity",
    cmap="RdYlGn_r",
    legend=True,
    linewidth=0.2,
    edgecolor="white",
    ax=ax,
)

ax.set_axis_off()
ax.set_title("Intermodal connectivity in minutes")
plt.tight_layout()
../_images/examples_2_indicators_24_0.png

Number of the services inside each area polygon. Example: fuel stations across region. You can pass a GeoDataFrame with any type of service (geometry type is Point).

[38]:
fuel_stations = gpd.read_file("data/tula_region_fuel_stations.geojson")

get_service_count(districts_polygons,service=fuel_stations).head()
[38]:
name geometry service_number
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 1
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 3
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 13
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 26
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 6

Accessibility (in minutes) of the services inside each area polygon. If the service is found inside the area, the accessibility equals to zero. Based on shortest path in the graph.

[39]:
service_accessibility = get_service_accessibility(settlement_points, G_drive, districts_polygons,
                            service=fuel_stations)
service_accessibility.head()
2026-04-04 23:09:35.297 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[39]:
name geometry service_accessibility
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 144.500
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 164.750
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 76.625
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 70.250
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 96.625
[40]:
fig, ax = plt.subplots(figsize=(10, 8))
service_accessibility.plot(
    column="service_accessibility",
    cmap="RdYlGn_r",
    legend=True,
    linewidth=0.2,
    edgecolor="white",
    ax=ax,
)

ax.set_axis_off()
ax.set_title("Fuel station accessibility in minutes")
plt.tight_layout()
../_images/examples_2_indicators_29_0.png

Number of bus routes intersecting the polygons.

[41]:
get_bus_routes_num(districts_polygons, public_transport_graph = G_pt).head()
/Users/sashamorozov/Documents/Code/tf_dpo/tf/transport_frames/indicators.py:439: UserWarning: Approach is not set. Defaulting to 'primal'.
  n, e = momepy.nx_to_gdf(public_transport_graph)
[41]:
name geometry bus_routes_count
0 Арсеньевский район POLYGON ((36.27046 53.67571, 36.27343 53.67505... 0
1 Белевский район POLYGON ((35.89856 53.85018, 35.90015 53.84679... 0
2 Богородицкий район POLYGON ((37.8624 53.73471, 37.86404 53.72565,... 1
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 0
4 Воловский район POLYGON ((37.73668 53.45977, 37.74516 53.45518... 0

Territory indicators

Indicators aggregated for one territory.

[42]:
territory = districts_polygons.iloc[[3]]
territory.plot()
[42]:
<Axes: >
../_images/examples_2_indicators_34_1.png

Number of the services inside territory polygon.

[43]:
get_terr_service_count(territory,
                            service=fuel_stations,
                            local_crs=local_crs).head()
[43]:
name geometry service_number
3 Веневский район POLYGON ((37.8212 54.32909, 37.82119 54.3291, ... 26

Accessibility (min) of the services inside territory polygon. If the service is found inside the area, the accessibility equals to zero.

Based on shortest path in the graph

[44]:
get_terr_service_accessibility(graph=G_drive,
                                     territory_polygon=territory,
                                     service=fuel_stations)
2026-04-04 23:09:40.814 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
/Users/sashamorozov/Documents/Code/tf_dpo/tf/.venv/lib/python3.11/site-packages/pandas/io/formats/format.py:1458: RuntimeWarning: overflow encountered in cast
  has_large_values = (abs_vals > 1e6).any()
[44]:
name geometry service_accessibility
3 Веневский район POLYGON ((37.8212 54.32909, 37.82119 54.3291, ... 0.0

Density of the roads inside territory polygon \(\mathrm{km/km^2}\).

[45]:
get_road_density(G_drive, territory)
[45]:
name geometry density
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 1.077431

Distance from center of the polygon to the administrative center of the region

[46]:
get_terr_distance_to_region_admin_center(region_admin_center, territory, G_drive)
2026-04-04 23:09:43.142 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[46]:
name geometry distance_to_admin_center
0 Веневский район POLYGON ((37.8212 54.32909, 37.82119 54.3291, ... 60.798

Shortest distance (in km) to nearest district and settlement points, which are laying in intersecting districts.

[47]:
get_terr_nearest_centers(territory, G_drive, districts_polygons,
                               settlement_points,local_crs)
2026-04-04 23:09:44.613 | WARNING  | Removing 197 nodes from 22 smaller strongly connected components. These are subgraphs where nodes are internally reachable but isolated from the rest. Retaining only the largest strongly connected component (31927 nodes).
[47]:
name geometry to_nearest_center_km
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 0.968

Number of bus routes intersecting the territory

[48]:
get_bus_routes_num(territory, public_transport_graph=G_pt).head()
/Users/sashamorozov/Documents/Code/tf_dpo/tf/transport_frames/indicators.py:439: UserWarning: Approach is not set. Defaulting to 'primal'.
  n, e = momepy.nx_to_gdf(public_transport_graph)
[48]:
name geometry bus_routes_count
3 Веневский район POLYGON ((37.86087 54.34286, 37.86265 54.34249... 0