My daily commute in Metro Manila used to take anywhere from 45 minutes to 2.5 hours. Same origin, same destination, wildly different travel times. After years of dealing with this, I decided to stop complaining and start mapping. I wanted to know: what does the full transit network actually look like when you lay it all out?
Turns out, it looks exactly as chaotic as it feels.
Where the Data Came From
The main data source is the GTFS (General Transit Feed Specification) feed from Sakay.ph, which has been crowd-sourcing transit route data for Manila. The feed includes route shapes, stop locations, and trip schedules for jeepneys, buses, and rail lines.
In total, the dataset covers 12,500+ jeepney routes, 1,200+ bus routes, and the 3 existing rail lines (LRT-1, LRT-2, and MRT-3). Each route has a set of GPS coordinates tracing its path, plus metadata about frequency and operating hours — though the quality of that metadata varies a lot.
How It Works
GTFS is a standard format created by Google, originally for Google Maps. It's a ZIP file containing several CSV files: routes.txt, trips.txt, stops.txt, stop_times.txt, and shapes.txt. Parsing it isn't hard, but making sense of the result is.
I built three analysis layers:
- Route overlap detection — identifying corridors where 50+ routes share the same road segment. These are the bottleneck streets where all the congestion concentrates.
- Stop density mapping — plotting every stop on a heatmap to show which areas are well-served and which are transit deserts.
- Mode comparison — comparing the geographic coverage of jeepneys vs. buses vs. rail to show how much of the network each mode handles.
I used geopandas for the spatial analysis and folium for the interactive maps. The trickiest part was matching route shapes to actual road segments, since GPS traces aren't perfectly aligned with OpenStreetMap road geometry.
Key Findings
The numbers confirmed what every Manila commuter already suspects, but they also revealed some things I didn't expect.
Jeepneys cover roughly 10 times more unique routes than buses. They're the backbone of the system — there's no getting around it. The jeepney modernization program makes economic sense, but any plan that reduces the number of routes without adding replacement service will leave huge gaps.
Quezon City has the highest density of transit stops in Metro Manila. That tracks — it's the largest city by area and population. But Makati, despite being the business center, has surprisingly thin coverage once you step away from the main EDSA corridor.
The rail system barely scratches the surface. Three lines for a metro area of over 13 million people. For comparison, Bangkok has 10 rail lines, and Kuala Lumpur has 12. The gap is staggering. Even when the planned subway and LRT extensions are finished, Manila will still be behind where its neighbors were a decade ago.
The most congested corridor? EDSA, obviously. But the data showed that Taft Avenue and Commonwealth Avenue are almost as route-dense, with over 70 overlapping routes each. These streets carry a disproportionate share of the entire network's load.
What I'd Do Differently
This project was a snapshot. Transit networks change constantly — routes get rerouted, new ones get added, old ones disappear. If I did this again, I'd set up a pipeline that pulls the GTFS feed weekly and tracks changes over time. That would let me see how the network evolves as the modernization program rolls out.
I'd also love to combine this with actual ridership data, but that's much harder to get. LTFRB doesn't publish route-level passenger counts, and the rail operators only release total daily ridership, not station-level data. Until that changes, we're working with route coverage as a proxy for actual service quality.
Want to see all the charts and data tables?
View the Full Analysis →