Are the San Francisco Muni routes well-named?
The beginning of the quest
San Franciscans love their public transit — it won’t take a week here for you to feel it. Hop on a J train on a Saturday morning to Dolores park, you’ll experience a packed car: tourists with fancy cameras, parents with cumbersome strollers, students with backpacks and guitar cases, and so many more people enjoying their weekend, all crammed in this tiny carriage that meanders its way through the narrow track between the walls and hedges — at a pace so slow I often wonder how anyone is willing to waste that much time, yet the car is full as always. Or you can sit in a secluded corner of a coffee shop and tune into the conversations around, after filtering out the AI startups and Leetcode problems, you’ll find discussions of Muni buses and BART trains coming up in no time.
Perhaps nothing captures the enthusiasm better than this game called Routle. A daily Muni-route guessing game sponsored by the San Francisco Standard. It’s a simple game: it gives you the outline of the route, you have 5 chances to guess it, and the outlines of the wrong guesses also show up.

This one is easy for me. It’s 48-Quintara/24th St. I ride it for my weekend jogs along the Great Highway. Many others — not so much. At first I could only come up with random guesses, but day after day I started getting better. Studying the route map posted on the bus shelters also became my favorite past-time activity as my rides got inevitably delayed. These lines form a pattern: 1-California runs cross-town in the north, then 2-Sutter parallel and below that; below 2 and in the place of 3 and 4 we have 38-Geary and 31-Balboa instead, then back to 5, 6, 7 in that order. 8-Bayshore and 9-San Bruno leads the north-south lines from east to west, followed by the lines in the 10s mostly vertically. The 20s mostly run in L-shapes bypassing downtown, and from that onwards each line chooses its own way.
You might have noticed something: each line has a name in addition to their number designation. The same holds for the light rail lines (N-Judah) and even the cable cars (CA-California Street). Unlike many transit agencies where the names are just conveniences during announcements, Muni route names are official. When the route number is obscure, the name becomes a useful clue — to some extent, at least. Most of the lines are named after the streets they run on, and some names are extremely accurate: like 14-Mission that runs almost entirely along Mission street, or 49-Van Ness/Mission that makes it way down from North Beach via Van Ness, and then Mission. Other names are absolutely terrible. 43-Masonic, for example, barely runs on Masonic avenue, as illustrated below.

It was on this Sunday that I was getting depressed benchmarking my proof system against these VC-backed million-dollar projects. I opened Routle. It was 35-Eureka — no chance I would get that right, because I have never heard of Eureka street; not that it matters, because that bus barely runs on Eureka street anyways. Out of frustration and desperation for doing something that does not involve fighting capitalism, I wondered: how accurate are these route names actually? Can they have more logical names?
What is considered a good route name, anyways?
My first instinct is, what percentage of each route actually runs on its named streets? To find out, all I need is to fetch the route data of each line somewhere, run a python script to compute the percentage of that line on the named street(s), and I’m done! A second valid question could be, what percentage of stops of each line are on its named streets? One can argue maybe this question is even better, since the riders wait at stops, not uniformly along the entire line. If I can fetch the route data itself, then obtaining a list of stops shouldn’t be hard — and that’s what I did, see the results below.
TL;DR, here’s the results.
I present the percentage of each street on each route:

Each route is a row on the graph, divided into one segment for every street it runs on. Streets with a higher share of the route is ordered more towards the left. I marked the first street in route name red, and the second named street, if exist, yellow. I also marked other notable features like tunnels, right-of-ways, and unavailable data. Finally, I subjectively decided that some routes are named after neighborhoods, and listed them in a separate category.
Next, percentage of stops on named streets:

The graph only checks if a stop name contains the street. A special stop, like Salesforce Transit Center, does not belong to any street; on the other hand, a stop like Portrero Ave & 21st St is counted towards both Portrero avenue and 21st street. When reasoning about percentage of stops on the named streets, these edge cases mostly do not affect the overall graph. However, if I were to list out the percentage of stops on every street, then all the stops at an intersection would be double-counted — for that reason, I put every stop not on the named streets in the “other” category.
What to conclude from this?
The routes are much better named than what I expected. Most routes are named after their longest street segment — or the longest segment after Market street, as we obviously can’t call every route “Market”. Some other names are debatable:
- 22-Fillmore/16th St seems like a more fitting name than 22-Fillmore. The two streets combined covers 78% of the entire route.
- The portion of Ashbury street in 33-Ashbury/18th St is rather low. However, the route likely named after Ashbury Heights than the street.
- 23-Monterey and 24-Divisadero are both named after their second-longest street segments, narrowly beaten by Sloat Boulevard and Castro Street, respectively. Their current names do sound cooler, though.
- 19-Polk should very much adopt a second name to reflect its long route. I’m not sure whether Rhode Island or Evans would be better.
- 35, 43, 44, 54, and 56 are where I’m truly lost. Maybe MUNI doesn’t want to name their bus after silver or diamond, but how do they decide on the current names?
Some other interesting details that I picked up:
- The California Street Cable Car, the only completely straight line in the system, is the unsurprising winner. Although 14-Mission comes close.
- The twin peaks tunnel is really long. It takes up almost 1/4 of each light rail line that passes through it.
- Some routes, despite named after the neighborhood, run on a street that shares its name with that neighborhood. In fact, some of these streets take up quite a portion of the route.
Other potential metric
A third, more obscure framing could be, what percentage of each route runs on its named streets on either direction? I originally favored that question because of one-way streets: for example, Geary street is one-way east of Japantown, so east-bound 38-Geary is forced to run on O’Farrell street. Only counting westbound 38, thus, would be more fair. However, this analysis produces misleading results: 1-California, for example, runs eastbound on Clay street and westbound on Sacramento street approaching downtown, but stays on California street both ways otherwise. Looking only at the westbound direction would therefore overstate the importance of Sacramento street. For this reason I chose to drop the directional analysis.

In more details: finding out where each line goes
Information about Muni routes can be downloaded from the MTC 511 open data portal. Doing so requires signing up to obtain a token for free. The name and location of every stop, as well as the geometric paths followed by each route, are available through the portal. I then use OpenStreetMap data to match the route shape to the streets of San Francisco. For routes with multiple branches, the dataset provides the share of scheduled service on each branch. This allows me to represent each route as a weighted combination of its branches.
The route-matching algorithm is mostly designed by ChatGPT. To match a route shape with the street map, it first projects the GTFS route geometry and the OpenStreetMap street network into the same coordinate system. It then divides the route into roughly 15-meter segments and match each segment, using its midpoint, against nearby OpenStreetMap streets within 35 meters.
Simply choosing the closest street is unreliable: near intersections, a midpoint may lie closer to a cross street than to the street the route actually follows. To reduce these errors, the matcher considers both distance and direction: streets that run at a substantially different angle from the route segment receive a larger penalty. It also considers continuity across consecutive samples, penalizing unnecessary changes from one street name to another. This makes a sequence of samples along the same street more likely to stay on that street rather than briefly switching to a cross street at an intersection.
Finally if the selected OpenStreetMap road is unnamed (most likely a transit way or highway ramp), the algorithm looks for a nearby named road no more than 15 meters away from the unnamed road, and aligned with the route within 30 degrees. The average block size in San Francisco is around 90 to 120 meters, so the probability of a false positive is low.
Below is a visualization of the algorithm on the southern section of 29. To make the graph readable, I only sampled a point every 150 meters. I marked the nearest road to each point, as well as final result of the matcher if it is different.

Special roadways
Despite the best adjustments, noticeable portions of some routes still match with unnamed roads, mostly along highway ramps or around Daly City transit center. I mark these sections gray in the graph with an “N/A” label.
Another noticeable issue is regarding to rail tunnels and dedicated right-of-ways. Naively handling so would, for example, match Twin Peaks tunnel with streets on the top of the hill, like Marview way. For tunnel segments under Market street or Stockton street, however, I do wish to match them with the street above-ground. In the end I hard-coded four segments for priority matching: Twin Peaks tunnel, Sunset tunnel, as well as the right-of-way around Dolores Park and Stonestown. Tunnel segments are marked light blue in the graph, and right-of-ways are in light green.

Expanding to other cities
While the general technique should be applicable across a wide range of cities across the world, whether the analysis would actually make sense in these cities is unclear. Route names are generally uncommon outside of a few North American cities; and even within the applicable cities, many has a much more radial transit network — most lines terminate in downtown, so they can simply adopt the other terminus as their route name. San Francisco is also unique in its layout — canyons and hills get into the way of the otherwise straight street grid. Streets end at the foot of the hills, or cross over them at a steep grade impassable to transit vehicles. It is this chaos within the tidiness that leads to the interesting result of this analysis, which adds even more charm to this amazing city.