Add one-click examples and route search by number or metadata, with transport type, location and map-area filters. Preserve search filters and bounds in shareable URLs and restore searches on reload and browser navigation. Validate with 91 passing tests, including desktop and mobile browser coverage, and strict mypy checks. Closes #2
188 lines
6.6 KiB
Markdown
188 lines
6.6 KiB
Markdown
# openstreetmap-tools
|
|
|
|
A collection of tools for working with OpenStreetMap public transport data.
|
|
|
|
## Tools
|
|
|
|
### osm-pt-geojson
|
|
|
|
Fetch an OSM public transport route relation and list its stops, or export the
|
|
route as GeoJSON.
|
|
|
|
#### CLI usage
|
|
|
|
```
|
|
osm-pt-geojson list-stations <relation_id>
|
|
osm-pt-geojson route-between <relation_id> <from_station> <to_station> [-o FILE]
|
|
osm-pt-geojson full-route <relation_id> [-o FILE]
|
|
```
|
|
|
|
**List stops on a route:**
|
|
```
|
|
$ osm-pt-geojson list-stations 18892969
|
|
Route: Bus A1: Bristol Airport → Bristol Bus Station
|
|
Stops (21):
|
|
1. Airport Terminal
|
|
2. Airport Tavern
|
|
...
|
|
21. Bus Station
|
|
```
|
|
|
|
**Export a segment between two stops as GeoJSON:**
|
|
```
|
|
$ osm-pt-geojson route-between 18892969 "Airport Terminal" "East Street" -o segment.geojson
|
|
```
|
|
|
|
**Export the full route as GeoJSON:**
|
|
```
|
|
$ osm-pt-geojson full-route 18892969 -o route.geojson
|
|
```
|
|
|
|
**Omit stop points from GeoJSON output:**
|
|
```
|
|
$ osm-pt-geojson full-route 18892969 --no-stops -o route.geojson
|
|
```
|
|
|
|
GeoJSON is written to stdout if `-o` is not given.
|
|
|
|
#### Output format
|
|
|
|
A GeoJSON `FeatureCollection` containing:
|
|
|
|
- A `LineString` feature for the route geometry, with `name`, `ref`, `from`,
|
|
`to`, and `route` properties from the OSM relation tags.
|
|
- A `Point` feature for each stop, with a `name` property (omitted with
|
|
`--no-stops`).
|
|
|
|
#### Installation
|
|
|
|
```
|
|
pip install osm-geojson
|
|
```
|
|
|
|
Or from source:
|
|
```
|
|
git clone https://git.4angle.com/edward/openstreetmap-tools
|
|
cd openstreetmap-tools
|
|
pip install -e .
|
|
```
|
|
|
|
---
|
|
|
|
### Web frontend
|
|
|
|
An interactive map interface for browsing and downloading public transport
|
|
routes as GeoJSON.
|
|
|
|
#### Features
|
|
|
|
- Search worldwide for public transport routes by route number, name,
|
|
destination, operator or network, with an optional transport type filter.
|
|
Click a result to load it; search uses Overpass and shows up to 50 matches.
|
|
- Narrow a route search with a location (for example, route `24`, location
|
|
`Bristol, UK`, transport type `Bus`). Choose a matching place to centre the
|
|
map and show its search boundary, or tick **Search this map area** to use
|
|
the current view instead. Routes may extend outside the search area.
|
|
- Share or bookmark the page URL after searching. It saves the route text,
|
|
transport type, selected location and exact area; opening it automatically
|
|
restores the filters and matching route list. Back and Forward restore
|
|
previous searches. Results reflect the latest OpenStreetMap data.
|
|
- Start with one-click examples: Bristol airport bus A1, Istanbul Metro M11,
|
|
or all M11 directions. No relation ID lookup is needed to try the tool.
|
|
- Enter a relation ID or OSM URL to load a route onto the map.
|
|
- Click stops in the sidebar list or on the map to set start and end points.
|
|
- Preview the selected segment highlighted on the map.
|
|
- Toggle stop points in/out of the GeoJSON before downloading.
|
|
- Download a segment or the full route as a `.geojson` file.
|
|
- Entering a `route_master` ID shows all directions on the map with links to
|
|
each individual route.
|
|
- Bookmarkable URLs: `/<relation_id>` loads that route directly.
|
|
|
|
#### Running the dev server
|
|
|
|
```
|
|
pip install -e ".[web]"
|
|
flask --app web/app.py run
|
|
```
|
|
|
|
Open `http://127.0.0.1:5000`.
|
|
|
|
#### API
|
|
|
|
The web frontend exposes a JSON API. Full documentation is available at `/docs`
|
|
when the server is running.
|
|
|
|
| Endpoint | Description |
|
|
|---|---|
|
|
| `GET /api/search?q=TEXT[&mode=TYPE][&south=S&west=W&north=N&east=E]` | Find public transport route relations, optionally within an area |
|
|
| `GET /api/locations?q=PLACE` | Find candidate locations and their search bounds |
|
|
| `GET /api/route/<id>` | Full route GeoJSON, stop list, and sibling routes |
|
|
| `GET /api/segment/<id>?from=NAME&to=NAME` | Segment between two named stops |
|
|
| `GET /api/route_master/<id>` | All member routes of a route_master |
|
|
|
|
---
|
|
|
|
### UK Bus Stop Finder
|
|
|
|
A mobile-friendly map for finding ATCO codes using the Department for Transport's
|
|
[NaPTAN dataset](https://beta-naptan.dft.gov.uk/download). It covers active public
|
|
transport stops in England, Scotland and Wales, including bus, rail, tram,
|
|
ferry and airport access points; Northern Ireland is not included.
|
|
|
|
Search by postcode, street, place, exact ATCO code, coordinates or browser
|
|
location. Place searches use Nominatim, with the visible map as a ranking bias.
|
|
The map loads stops at zoom level 15 or closer. Selecting a stop shows its
|
|
NaPTAN fields and looks up bus routes in OpenStreetMap by matching its ATCO code.
|
|
OSM route coverage may be incomplete; NaPTAN itself does not contain routes or
|
|
live departures. An Overpass outage does not prevent NaPTAN stop searches.
|
|
|
|
Searches have shareable `?q=...` and `?lat=...&lon=...` URLs; a selected NaPTAN
|
|
stop uses `?naptan=010000056`. Existing `?node=...`, `?way=...` and
|
|
`?relation=...` OSM links still work.
|
|
|
|
Download the national CSV from NaPTAN, then import it and start the app:
|
|
|
|
```sh
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install -e ".[web]"
|
|
.venv/bin/uk-bus-stops-import-naptan Stops.csv
|
|
.venv/bin/flask --app uk_bus_stops.app run
|
|
```
|
|
|
|
The importer uses SQLite's built-in R-tree spatial index; no database server or
|
|
SpatiaLite extension is required. It preserves leading zeros in ATCO codes,
|
|
converts British National Grid coordinates when latitude/longitude are absent,
|
|
and reports imported, inactive/pending, invalid and converted row counts.
|
|
Only active records with usable positions are included. The original CSV fields
|
|
remain available in the detail panel. XML is not needed.
|
|
|
|
The default database is `data/naptan.sqlite3` in the project directory. Set
|
|
`NAPTAN_DATABASE=/absolute/path/naptan.sqlite3` for both import and serving, or
|
|
use `--database PATH` for the importer. The serving process needs read access.
|
|
To refresh, download a new CSV and rerun the same command. It builds a temporary
|
|
database alongside the destination and replaces the old snapshot atomically;
|
|
a failed import leaves the old snapshot intact. Downloads and databases are
|
|
excluded from git. The app returns a JSON 503 with import instructions if its
|
|
database is missing or unreadable.
|
|
|
|
NaPTAN is the default stop source. Set `UK_BUS_STOPS_SOURCE=osm` to retain
|
|
Overpass stop searches instead. OSM route queries use `overpass.atownsend.org.uk`,
|
|
with `overpass.private.coffee` as a fallback.
|
|
|
|
The production URL is `https://openstreetmap.tools/uk-bus-stops/`.
|
|
The app's `/about` page documents shareable URL parameters, map behaviour,
|
|
data sources, privacy considerations, and JSON endpoints.
|
|
|
|
Browser tests use Python Playwright. After installing the development extras,
|
|
install Chromium once and run the suite:
|
|
|
|
```
|
|
playwright install chromium
|
|
pytest tests/
|
|
```
|
|
|
|
---
|
|
|
|
## Licence
|
|
|
|
MIT License. Copyright (c) 2026 Edward Betts.
|