Convert GTFS feeds to GeoJSON with optional Folium preview maps.
Project description
gtfs2geojson
Convert any GTFS feed (zip file or directory) into a clean, styled GeoJSON FeatureCollection, with an optional interactive Folium preview map.
Built for transit data folks who want a quick, dependency-light way to go from gtfs.zip → something they can drop into kepler.gl, QGIS, deck.gl, Mapbox, or a Leaflet/Folium map — without spinning up Postgres/PostGIS.
Features
- Single command, no database:
gtfs2geojson feed.zip -o feed.geojson - Reads zip or directory GTFS sources, handles UTF-8 BOM
- Routes as MultiLineString features, one per
route_id(all shape variants merged) - Stops as Point features
- Mode-aware styling — readable labels (Bus / Metro / Tram / Ferry / Trolleybus / …) with sensible default colours, falling back from
route_colorwhen missing - Reconstructs missing geometry from
stop_timeswhen a route has no entry inshapes.txt(common for metros/trams in older feeds) - Filters: by mode (
--mode Bus), by agency (--agency OASA), by bounding box (--bbox w,s,e,n), by service day (--date 20260615) - Line simplification with Ramer-Douglas-Peucker (
--simplify 0.0001) for smaller, faster-rendering output - Output formats: standard GeoJSON or GeoJSON-seq (
--format geojsonseq) for tippecanoe / ogr2ogr pipelines - Introspection:
--list-modesand--list-agencies(with--json) to peek at a feed without converting - Optional Folium preview with per-mode toggleable layers, mode legend, summary sidebar, stop search, and configurable tiles (
--tiles dark_matter) - Extended GTFS route types supported (HVT codes 100–1700)
Install
pip install gtfs2geojson # core
pip install "gtfs2geojson[preview]" # also installs folium for --preview
Or from source:
git clone https://github.com/acesonic7/gtfs2geojson
cd gtfs2geojson
pip install -e ".[preview]"
CLI
# basic
gtfs2geojson feed.zip -o feed.geojson
# with interactive map (CARTO Positron tiles by default)
gtfs2geojson feed.zip -o feed.geojson --preview map.html
# dark basemap for nighttime / dataviz
gtfs2geojson feed.zip --preview map.html --tiles dark_matter
# filter to buses + metro inside a bbox, skip stops
gtfs2geojson feed.zip \
--mode Bus --mode Metro \
--bbox 23.6,37.9,23.8,38.05 \
--no-stops \
-o athens_core.geojson
# only trips active on a particular calendar date (combines calendar.txt
# weekday rules with calendar_dates.txt exceptions)
gtfs2geojson feed.zip --date 20260615 -o that_monday.geojson
# simplify polylines for web/mobile rendering (~10 m at most latitudes)
gtfs2geojson feed.zip --simplify 0.0001 -o feed.simplified.geojson
# pipe straight into tippecanoe (GeoJSON-seq, one Feature per record)
gtfs2geojson feed.zip --format geojsonseq | tippecanoe -o feed.mbtiles
# peek at what a feed contains, without converting
gtfs2geojson feed.zip --list-modes
gtfs2geojson feed.zip --list-agencies --json | jq '.[] | select(.n_routes > 5)'
# feed already extracted to a directory
gtfs2geojson ./gtfs_extracted/ -o feed.geojson
Stream to stdout (default) for piping into other tools:
gtfs2geojson feed.zip | jq '.features | length'
Python API
from gtfs2geojson import convert, write, list_modes, list_agencies
from gtfs2geojson.preview import render
geo = convert(
"feed.zip",
modes=["Bus", "Trolleybus"],
bbox=(23.6, 37.9, 23.8, 38.05),
service_date="2026-06-15", # also accepts "20260615" or datetime.date
simplify_tolerance=0.0001, # ~10 m perpendicular tolerance
include_stops=True,
)
write(geo, "feed.geojson") # default
write(geo, "feed.geojsonseq", format="geojsonseq") # one Feature per RFC-8142 record
render(geo, "preview.html", title="Athens core network", tiles="dark_matter")
# Peek at a feed without converting
list_modes("feed.zip") # -> {"Bus": 42, "Metro": 3, ...}
list_agencies("feed.zip") # -> [{"agency_id": "OASA", "agency_name": "OASA", "n_routes": 45}, ...]
Output schema
Each route feature carries:
| Property | Description |
|---|---|
feature_type |
always "route" |
route_id, route_short_name, route_long_name |
from routes.txt |
route_type |
original GTFS integer |
mode |
human label (Bus, Metro, Tram, Ferry, …) |
route_color, route_text_color |
hex strings, with mode-based defaults |
agency_id, agency_name |
joined from agency.txt |
headsigns |
up to 6 distinct headsigns concatenated with | |
shape_source |
"shapes.txt" or "stop_sequence" (reconstructed) |
n_trips |
number of trips serving this route |
n_stops |
number of distinct stops touched by any trip on this route |
length_km |
total network length, sum of all shape variants (haversine, km) |
Stop features carry:
| Property | Description |
|---|---|
feature_type |
always "stop" |
stop_id, stop_name, stop_code |
from stops.txt |
route_ids |
sorted list of routes serving this stop |
modes |
sorted list of distinct modes among those routes |
By default, stops not served by any kept trip are dropped — pass --keep-orphan-stops
(CLI) or keep_orphan_stops=True (Python) to retain them. If stop_times.txt is
absent, all stops are kept regardless.
Why?
Converting GTFS to GeoJSON should be a one-liner. Most existing options either:
- require Postgres/PostGIS (too heavy for a quick visualisation),
- assume
shapes.txtis always present (it isn't — many metros, trams, and older feeds skip it), - or output undecorated geometries with no styling hooks.
gtfs2geojson aims to be the boring, dependable, do-one-thing tool you can plug into a Makefile or notebook.
Limitations / non-goals
- No frequency or schedule data on the output.
- No realtime (GTFS-RT) support — schedule feeds only.
If you need any of the above, gtfs_kit and partridge are excellent.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gtfs2geojson-0.5.0.tar.gz.
File metadata
- Download URL: gtfs2geojson-0.5.0.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b993fc5b9325e53c5f5e8100de360d41b4f6f05825724628519c328593b6153b
|
|
| MD5 |
8752cbe15bff1ff7524d10511789992f
|
|
| BLAKE2b-256 |
f214c3df9bb28f3c73ba8aba9dc4267939cc032e83f8feb4bb180e26b549f8ed
|
Provenance
The following attestation bundles were made for gtfs2geojson-0.5.0.tar.gz:
Publisher:
publish.yml on acesonic7/gtfs2geojson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gtfs2geojson-0.5.0.tar.gz -
Subject digest:
b993fc5b9325e53c5f5e8100de360d41b4f6f05825724628519c328593b6153b - Sigstore transparency entry: 1392774788
- Sigstore integration time:
-
Permalink:
acesonic7/gtfs2geojson@40f5636685595235bd1c978d90d81a422717fd58 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/acesonic7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40f5636685595235bd1c978d90d81a422717fd58 -
Trigger Event:
release
-
Statement type:
File details
Details for the file gtfs2geojson-0.5.0-py3-none-any.whl.
File metadata
- Download URL: gtfs2geojson-0.5.0-py3-none-any.whl
- Upload date:
- Size: 18.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0f12b420508de31ba53d55f91defb298bcbd7131b99da90d28087bb0422517f
|
|
| MD5 |
879225df1ecf1a0cee5c1810e1571bc3
|
|
| BLAKE2b-256 |
30f17c4eb150eb7668eac9f639d48caffa0efcf90d221b1555b3b2a9093b1497
|
Provenance
The following attestation bundles were made for gtfs2geojson-0.5.0-py3-none-any.whl:
Publisher:
publish.yml on acesonic7/gtfs2geojson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gtfs2geojson-0.5.0-py3-none-any.whl -
Subject digest:
e0f12b420508de31ba53d55f91defb298bcbd7131b99da90d28087bb0422517f - Sigstore transparency entry: 1392774808
- Sigstore integration time:
-
Permalink:
acesonic7/gtfs2geojson@40f5636685595235bd1c978d90d81a422717fd58 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/acesonic7
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@40f5636685595235bd1c978d90d81a422717fd58 -
Trigger Event:
release
-
Statement type: