{ "cells": [ { "cell_type": "markdown", "id": "fa4563c984470740", "metadata": {}, "source": [ "# Isochrones\n", "\n", "This notebook builds isochrones on an intermodal `UrbanGraph` from IduEdu (walk + public transport):\n", "\n", "- `get_graph_isochrones` with `geometry_type=\"radius\"` and `\"ways\"` for one origin;\n", "- `get_stepped_graph_isochrones` with bands of width `step` for `\"radius\"`, `\"ways\"` and `\"separate\"`.\n", "\n", "The method is described on the [isochrones page](../isochrones.rst). The interactive maps show a light copy of every\n", "result (`for_map`: outlines simplified by 2 m), which keeps the notebook small.\n", "\n", "The last section, *Your own area*, shows what to replace to get the same pictures for another territory." ] }, { "cell_type": "code", "execution_count": 1, "id": "9e7d002c63864de6", "metadata": { "ExecuteTime": { "end_time": "2026-07-10T10:07:42.447914Z", "start_time": "2026-07-10T10:07:42.444986Z" }, "execution": { "iopub.execute_input": "2026-11-06T16:15:18.878933Z", "iopub.status.busy": "2026-11-06T16:15:18.878933Z", "iopub.status.idle": "2026-11-06T16:15:18.882451Z", "shell.execute_reply": "2026-11-06T16:15:18.882451Z" } }, "outputs": [], "source": [ "# Install required packages (uncomment if needed)\n", "# !pip install objectnat iduedu" ] }, { "cell_type": "code", "execution_count": 2, "id": "ebe2025fab286b4e", "metadata": { "ExecuteTime": { "end_time": "2026-07-10T10:07:50.570317Z", "start_time": "2026-07-10T10:07:42.622718Z" }, "execution": { "iopub.execute_input": "2026-11-06T16:15:18.883963Z", "iopub.status.busy": "2026-11-06T16:15:18.883963Z", "iopub.status.idle": "2026-11-06T16:15:21.480888Z", "shell.execute_reply": "2026-11-06T16:15:21.480888Z" } }, "outputs": [], "source": [ "import geopandas as gpd\n", "import iduedu\n", "from iduedu import get_4326_boundary, get_intermodal_graph\n", "from shapely import Point\n", "\n", "from objectnat import get_graph_isochrones, get_stepped_graph_isochrones" ] }, { "cell_type": "code", "execution_count": 3, "id": "0ab5bbe7", "metadata": { "execution": { "iopub.execute_input": "2026-11-06T16:15:21.482995Z", "iopub.status.busy": "2026-11-06T16:15:21.482995Z", "iopub.status.idle": "2026-11-06T16:15:21.644937Z", "shell.execute_reply": "2026-11-06T16:15:21.644937Z" } }, "outputs": [], "source": [ "import folium\n", "\n", "\n", "def for_map(gdf, tolerance=2.0):\n", " \"\"\"A light copy for a web map: outlines simplified by `tolerance` metres, coordinates rounded to about 10 cm.\"\"\"\n", " local = gdf.to_crs(gdf.estimate_utm_crs())\n", " local[\"geometry\"] = local.simplify(tolerance)\n", " light = local.to_crs(4326)\n", " light[\"geometry\"] = light.geometry.set_precision(1e-6)\n", " return light[~light.is_empty]\n", "\n", "def grey_tiles():\n", " \"\"\"Light grey base map (Esri World Light Gray); its tiles end at zoom 16 and are stretched beyond it.\"\"\"\n", " return folium.TileLayer(\"Esri.WorldGrayCanvas\", max_zoom=19, max_native_zoom=16)" ] }, { "cell_type": "markdown", "id": "494425a561aa50ec", "metadata": {}, "source": [ "## 1. Intermodal graph\n", "\n", "The graph covers the district and is clipped to its boundary. Edge weights are `time_min` (minutes) and\n", "`length_meter` (metres)." ] }, { "cell_type": "code", "execution_count": 4, "id": "df20dec8ac67c8da", "metadata": { "ExecuteTime": { "end_time": "2026-07-10T10:07:54.215395Z", "start_time": "2026-07-10T10:07:50.572833Z" }, "collapsed": false, "execution": { "iopub.execute_input": "2026-11-06T16:15:21.647417Z", "iopub.status.busy": "2026-11-06T16:15:21.647417Z", "iopub.status.idle": "2026-11-06T16:15:27.547355Z", "shell.execute_reply": "2026-11-06T16:15:27.547355Z" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d20e99012c9048329fe1744c56f5f4f3", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Parsing ground PT routes: 0%| | 0/57 [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "\u001b[32m2026-11-06 19:15:27.509\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36miduedu.graph.transformers\u001b[0m:\u001b[36mkeep_largest_connected_component\u001b[0m:\u001b[36m64\u001b[0m - \u001b[33m\u001b[1mRemoving 338 nodes outside the largest strongly connected component. Retaining 21181 of 21519 nodes.\u001b[0m\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\u001b[32m2026-11-06 19:15:27.542\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36miduedu.graph_builders.intermodal_builders\u001b[0m:\u001b[36mjoin_pt_walk_graph\u001b[0m:\u001b[36m248\u001b[0m - \u001b[33m\u001b[1mPublic transport nodes dropped with the smaller components: {'trolleybus': 2}\u001b[0m\n" ] } ], "source": [ "# Vasilyevsky Island district, Saint Petersburg (OSM relation 1114252).\n", "# IduEdu cuts the territory out of the Geofabrik extract (pip install \"iduedu[pbf]\");\n", "# without the `with` block the same calls query the Overpass API.\n", "with iduedu.use_pbf(osm_id=1114252, region=\"northwestern-fed-district\"):\n", " poly = get_4326_boundary(osm_id=1114252)\n", " G_intermodal = get_intermodal_graph(territory=poly, clip_by_territory=True)" ] }, { "cell_type": "markdown", "id": "917bf19ff192faac", "metadata": {}, "source": [ "## 2. Origin\n", "\n", "One origin point in WGS 84; it is snapped to the nearest graph node." ] }, { "cell_type": "code", "execution_count": 5, "id": "f6045b6fa1bc7c37", "metadata": { "ExecuteTime": { "end_time": "2026-07-10T10:07:58.194879Z", "start_time": "2026-07-10T10:07:58.190066Z" }, "execution": { "iopub.execute_input": "2026-11-06T16:15:27.549427Z", "iopub.status.busy": "2026-11-06T16:15:27.549427Z", "iopub.status.idle": "2026-11-06T16:15:27.554116Z", "shell.execute_reply": "2026-11-06T16:15:27.554116Z" } }, "outputs": [], "source": [ "# Define a single point of interest\n", "point = gpd.GeoDataFrame(geometry=[Point(30.27060176, 59.93546846)], crs=4326)" ] }, { "cell_type": "markdown", "id": "7127732b199acab6", "metadata": {}, "source": [ "## 3. Radius isochrone\n", "\n", "Union of buffers around the nodes reachable within 10 minutes, each with the residual budget converted to a\n", "distance with the median edge speed of the graph." ] }, { "cell_type": "code", "execution_count": 6, "id": "f71a6d15e3dc7eed", "metadata": { "ExecuteTime": { "end_time": "2026-07-10T10:08:02.722106Z", "start_time": "2026-07-10T10:07:58.938990Z" }, "execution": { "iopub.execute_input": "2026-11-06T16:15:27.556262Z", "iopub.status.busy": "2026-11-06T16:15:27.555259Z", "iopub.status.idle": "2026-11-06T16:15:33.280216Z", "shell.execute_reply": "2026-11-06T16:15:33.280216Z" } }, "outputs": [ { "data": { "text/html": [ "