Skip to content
Home Projects Blog Transit Analysis
Transit Analysis Python GTFS Data 2024

What Metro Manila’s Transit Map Leaves Out

OpenStreetMap has 803 bus routes for Metro Manila and 26 jeepney routes. The city runs jeepneys in the thousands. This page is about that gap — what a volunteer map records, what it misses, and why the pattern is not random.

803
Bus routes mapped
26
Jeepney routes mapped
4,438
Stop and station nodes
49
Rail stations
Data Source
Coverage Area
Metro Manila — 16 Cities & Municipalities (619.57 km²)
Tech Stack
Python Pandas Chart.js HTML/CSS GTFS
Key Takeaways

Every number here counts what has been mapped, not what exists. That sounds like a disclaimer. It is the finding: the formal network is mapped almost completely, and the informal one that moves most people is barely mapped at all.

  • 803 bus routes against 26 jeepney routes — a ratio of 31 to one, in a city where jeepneys outnumber buses many times over.
  • The rail network, by contrast, looks complete: 6 lines and 49 stations, all of them named.
  • Mapping is concentrated. Quezon City and Manila hold 49.7% of all mapped road stops between them, and Quezon City alone has 53 times as many as Pateros.
  • Even the tagging splits along the same line: 90.0% of bus routes record an operator against 42.3% of jeepney routes.
01

What Got Mapped

Route relations in OpenStreetMap inside the Metro Manila bounding box, by mode. Read this as a picture of mapping effort, not of service.

Mapped route relations by mode

Bus routes

803

Nearly all named, most with an operator recorded.

Jeepney routes

26

Tagged share_taxi. Metro Manila runs thousands of jeepney routes; twenty-six are in the map.

Ratio

31×

Bus routes per jeepney route in OSM. On the road the ratio runs the other way.

02

The Part That Is Complete

Rail is the exception, and the contrast is what makes the rest legible. Fixed infrastructure with a published timetable and a corporate owner gets mapped; a route that exists because drivers agree it does, does not.

Rail stations by city

Rail lines

6

Counted as distinct lines. OSM models each direction as its own relation, so the raw relation count doubles the network.

Stations

49

Every one carries a name — 100% named, against 98.6% of bus stops.

Cities with no station

5 of 17

Including Marikina, Navotas and Las Piñas. Rail coverage is genuinely uneven, and here the map and the world agree.

03

Where The Stops Are

Mapped road stops by local government unit, all 17 of them. The spread is wider than population or land area explains.

Mapped road stops by city

Quezon City

1,219

The most mapped city in the metro.

Pateros

23

The least. A 53-fold spread.

Top two combined

49.7%

Of all mapped road stops in the metro, in two of 17 cities.

04

Even The Tags Split

An operator tag says who runs the route. It is the kind of detail added by someone with access to official information, and it divides the same way everything else does.

Share of routes carrying an operator tag

Bus routes

90.0%

Record an operator.

Jeepney routes

42.3%

Fewer than half. Jeepney routes are run by cooperatives and individual franchises, and that is harder to look up than a bus company.

Bus stops named

98.6%

Of 4,029 mapped bus stops. Naming is the easy part; knowing who operates the service is not.

05

A Bug Worth Showing You

The first version of the city table credited San Juan — Metro Manila's smallest city, about 6 km² — with 948 bus stops. That is more than Manila. It sat in a chart looking entirely ordinary.

What happened

Each city was queried by name: area["name"="San Juan"]. Six administrative boundaries worldwide carry that name — Metro Manila, Negros Oriental, Batangas, Puerto Rico, Honduras, El Salvador. Overpass unioned them and returned one total. San Juan, Puerto Rico has a real bus network.

Why it was invisible

It returned a plausible number. Nothing errored, nothing was empty, the totals still summed. The only tell was domain knowledge: San Juan is small, and 948 stops is not.

The fix

Boundaries are now fetched once inside the metro box, matched by name there, and each city queried by its own relation id — recorded in the CSV. A name resolving to zero or more than one relation is a hard error. San Juan now reads 59 mapped stops instead of 948, and the metro's genuine floor turns out to be Pateros with 23.

06

What This Page Does Not Cover

The version this replaces charted ridership, busiest corridors, stop spacing, transfer hubs, service hours, route overlap and population per stop. None of those can be built from what is actually available here.

Ridership and service hours

LRTA and the MRT-3 operator publish ridership, and DOTr aggregates it — in press releases and PDFs. dotr.gov.ph returns 403 to scripts. OSM has geometry, never passengers.

Corridors, transfers, overlap

All of these need complete route geometry to mean anything. With jeepney routes at 26 of several thousand, a "busiest corridor" computed from this data would describe the mapping, not the traffic.

Population per stop

Needs population on the same boundaries. Doable with WorldPop, and worth doing — but it would inherit the coverage gap above and produce a confident number about a network that is mostly missing.

07

Method

One fetcher, five CSVs, Overpass only.

Extent is a bounding box

14.35–14.80°N, 120.90–121.15°E. The Metro Manila admin relation does not resolve by name in Overpass, so the box is the definition — and it is carried on every row, because it moves every number.

Cities by relation id

Never by name. See section 05. The seventeen NCR local government units are named explicitly rather than taken from the box, because the box also contains Bacoor, Antipolo and half of Bulacan.

Directions are deduplicated

OSM models each direction of a rail line as its own relation, so the raw count is fourteen for 6 lines. Counting relations would double the network.

Queries are cached

Overpass is a free community endpoint under real load. It answered with 429s, 504s and bare connection drops during this build — a dropped connection is not a URLError, which killed one run after thirteen of seventeen cities. Responses are cached so a re-run resumes rather than repeating the work.

Counts are floors

Nothing here is a count of Metro Manila's transport system. Everything is a count of what has been mapped. The two are not close for road-based transport, and a standing warning in checks.sql fires while jeepney coverage stays under 500 routes.

Verification

Eleven assertions in checks.sql, including one that fails if any single city holds more than half the metro's stops — the exact signature of the boundary bug in section 05.

08

Key Findings & Summary

  • OpenStreetMap holds 803 bus routes and 26 jeepney routes for Metro Manila — 31 to one, in a city where the real ratio runs the other way.
  • Rail is essentially complete: 6 lines, 49 stations, all named. Formal infrastructure with an owner and a timetable gets recorded; a route that exists because drivers agree it does does not.
  • Mapping is concentrated: Quezon City and Manila hold 49.7% of all 3,969 mapped road stops between them.
  • 5 of 17 NCR cities have no mapped rail station at all — and here the map and the world agree.
  • The formal/informal split reaches into the tags: 90.0% of bus routes record an operator against 42.3% of jeepney routes.

Sources & Citations

Every figure on this page traces to one of these, through a CSV in data/ph-transit/. Each is checked against its source query on every build.

OpenStreetMap via Overpass APIPrimary

Public transport routes and stops in 14.35-14.80N/120.90-121.15E — Volunteer-mapped; coverage of road-based transport is partial and every count is a floor

Let's Discuss This Analysis

Interested in urban transit data analytics or transportation planning research?

Have a dataset you'd like analyzed or need a mini AI project as a starter guide? Send me your suggestions!

Prefer the plain-English version?

I wrote a companion post — “The Map Has 26 Jeepney Routes” — in simple, everyday words.

Read the blog post →