Skip to content

Instantly share code, notes, and snippets.

@hollemawoolpert
Last active January 3, 2022 14:17
Show Gist options
  • Save hollemawoolpert/2dddca06081a4798d8878f5ad522ad2a to your computer and use it in GitHub Desktop.
Save hollemawoolpert/2dddca06081a4798d8878f5ad522ad2a to your computer and use it in GitHub Desktop.
Find arriving bus with Shapely

Binder

Find closest arriving bus

Uses Shapely basic linear referencing capabilities to find nearest bus to each stop.

Run on binder

Run locally

Prerequisites

  • Python 3 environment
  • JupyterLab
pip install jupyterlab

Installation

pip install -r requirements.txt

Run notebook

jupyter notebook
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Map out the route\n",
"Waypoints define the route geometry. Stops are stops. Bus positions are the locations of the buses along the route for a given moment in time."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"route: MULTILINESTRING ((1 0, 2 0), (2 0, 3 2), (3 2, 3 3), (3 3, 2 3), (2 3, 0 3), (0 3, 0 2), (0 2, 1 2), (1 2, 1 0))\n"
]
}
],
"source": [
"from shapely.geometry import Point, LineString, MultiLineString\n",
"\n",
"waypoints = [((1,0),(2,0)),((2,0),(3,2)),((3,2),(3,3)),((3,3),(2,3)),((2,3),(0,3)),((0,3),(0,2)),((0,2),(1,2)),((1,2),(1,0))]\n",
"stops = [(3,2),(2,3),(1,2)] # 3 stops\n",
"bus_positions = [(1,0),(3,3),(1.5,3),(0,2)] # 4 buses\n",
"route = MultiLineString(waypoints)\n",
"print('route: ', route)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Calculate the distances along the route for each stop and bus\n",
"Find the closest arriving bus. The closest arriving bus is not necessarily the closest because it could have passed the stop. The linear referencing function we use for projecting distance honors directionality along the route."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"STOP 1\n",
"distance along route: 3.236068\n",
"\tbus 1\n",
"\t\tdistance along route: 0.000000\n",
"\t\tdistance to stop: 3.236068\n",
"\t\tbus is inbound: True\n",
"\tbus 2\n",
"\t\tdistance along route: 4.236068\n",
"\t\tdistance to stop: -1.000000\n",
"\t\tbus is inbound: False\n",
"\tbus 3\n",
"\t\tdistance along route: 5.736068\n",
"\t\tdistance to stop: -2.500000\n",
"\t\tbus is inbound: False\n",
"\tbus 4\n",
"\t\tdistance along route: 8.236068\n",
"\t\tdistance to stop: -5.000000\n",
"\t\tbus is inbound: False\n",
"\tCLOSEST BUS: 1, distance: 3.236068\n",
"\n",
"STOP 2\n",
"distance along route: 5.236068\n",
"\tbus 1\n",
"\t\tdistance along route: 0.000000\n",
"\t\tdistance to stop: 5.236068\n",
"\t\tbus is inbound: True\n",
"\tbus 2\n",
"\t\tdistance along route: 4.236068\n",
"\t\tdistance to stop: 1.000000\n",
"\t\tbus is inbound: True\n",
"\tbus 3\n",
"\t\tdistance along route: 5.736068\n",
"\t\tdistance to stop: -0.500000\n",
"\t\tbus is inbound: False\n",
"\tbus 4\n",
"\t\tdistance along route: 8.236068\n",
"\t\tdistance to stop: -3.000000\n",
"\t\tbus is inbound: False\n",
"\tCLOSEST BUS: 2, distance: 1.000000\n",
"\n",
"STOP 3\n",
"distance along route: 9.236068\n",
"\tbus 1\n",
"\t\tdistance along route: 0.000000\n",
"\t\tdistance to stop: 9.236068\n",
"\t\tbus is inbound: True\n",
"\tbus 2\n",
"\t\tdistance along route: 4.236068\n",
"\t\tdistance to stop: 5.000000\n",
"\t\tbus is inbound: True\n",
"\tbus 3\n",
"\t\tdistance along route: 5.736068\n",
"\t\tdistance to stop: 3.500000\n",
"\t\tbus is inbound: True\n",
"\tbus 4\n",
"\t\tdistance along route: 8.236068\n",
"\t\tdistance to stop: 1.000000\n",
"\t\tbus is inbound: True\n",
"\tCLOSEST BUS: 4, distance: 1.000000\n"
]
}
],
"source": [
"def calc_bus_dist(bus_idx, bus_pos):\n",
" bus_point = Point(bus_pos)\n",
" bus_lrs = route.project(bus_point)\n",
" print('\\tbus %i' % (bus_idx+1))\n",
" print('\\t\\tdistance along route: %f' % bus_lrs)\n",
" return bus_lrs\n",
"\n",
"stop_idx = 0\n",
"for stop in stops:\n",
" print('\\nSTOP %i' % (stop_idx+1))\n",
" stop_point = Point(stop)\n",
" stop_lrs = route.project(stop_point)\n",
" print('distance along route: %f' % stop_lrs)\n",
" \n",
" bus_idx = 0\n",
" stop_bus_distances = []\n",
" arriving_buses = []\n",
" for bus_pos in bus_positions:\n",
" bus_lrs = calc_bus_dist(bus_idx, bus_pos)\n",
" stop_bus_dist = stop_lrs - bus_lrs\n",
" print('\\t\\tdistance to stop: %f' % stop_bus_dist)\n",
" stop_bus_distances.append(stop_bus_dist)\n",
" \n",
" bus_is_coming = stop_bus_dist > 0\n",
" print('\\t\\tbus is inbound: %s' % bus_is_coming)\n",
" if bus_is_coming:\n",
" arriving_buses.append((bus_idx, stop_bus_dist))\n",
" bus_idx = bus_idx+1\n",
" \n",
" if len(arriving_buses):\n",
" closest_bus = min(arriving_buses, key=lambda n: (n[1], -n[0]))\n",
" print('\\tCLOSEST BUS: %i, distance: %f' % (closest_bus[0]+1,closest_bus[1]))\n",
" \n",
" stop_idx = stop_idx+1"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Shapely==1.6.4.post2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment