Visualizing Caltrain Ridership - 2016 Weekday Average

This notebook is contains a set of timetable visualizations built with open data published by Caltrain. You can view the project on GitHub.

In [1]:
from collections import defaultdict
from gtfslib.dao import Dao
from gtfslib.model import CalendarDate, Route, Trip
from gtfslib.utils import fmttime
from ipy_table import make_table
from itertools import tee
import networkx as nx
from nxpd import draw
import pandas as pd

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2,s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

def transpose(list_of_lists):
    return list(map(list, zip(*list_of_lists)))
In [2]:
dao = Dao()
# Feed includes service from 2016
dao.load_gtfs("./data/Caltrain-2016-08-18.zip", disable_normalization=True)
In [3]:
fltr = (
    (CalendarDate.date=="2016-06-08") &
    (Trip.direction_id=="1") &
    Route.route_id.in_([
        'Bu-16APR', # Baby Bullet
        'Li-16APR', # Limited
        'Lo-16APR'  # Local
    ]))

# Sort by stop time since all trips begin at the same stop
def trip_sort(trip):
    start = trip.stop_times[0]
    return start.arrival_time or start.departure_time

trips = sorted([t for t in dao.trips(fltr=fltr)], key=trip_sort)
In [4]:
patterns = set()

for trip in trips:
    pattern = tuple(st.stop_id for st in trip.stop_times)
    patterns.add(pattern)
In [5]:
G = nx.DiGraph()

# Build a pattern graph
for pattern in patterns:
    for a, b in pairwise(pattern):
        G.add_edge(a, b)

# Label nodes with stop names
for stop_id, data in G.nodes(data=True):
    stop = dao.stop(stop_id)
    data["label"] = stop.stop_name.split("Caltrain")[0].strip()
In [6]:
df = pd.read_csv("./data/2016 Average Weekday Passenger Counts by Train.csv")

ridership = {}
for _, row in df.iterrows():
    trip_short_name = str(row["trip_short_name"])
    stop_name = row["stop_name"]
    if trip_short_name not in ridership:
        ridership[trip_short_name] = {}
    ridership[trip_short_name][stop_name] = dict(row)
In [7]:
# This only works if the patterns form a directed-acyclic graph
header = [G.node[stop_id]["label"] for stop_id in nx.topological_sort(G)]
In [8]:
draw(G, show='ipynb')
Out[8]:
In [9]:
def build_trip_row(trip, cell_func):
    row = [trip.trip_short_name]
    stop_ridership = ridership[trip.trip_short_name]
    # assumes one visit per stop
    stimes_by_stop_name = {G.node[st.stop_id]["label"]: st for st in trip.stop_times}
    for stop_name in header:
        if stop_name in stop_ridership and stop_name in stimes_by_stop_name:
            stime = stimes_by_stop_name[stop_name]
            riders = stop_ridership[stop_name]
            value = cell_func(stime, riders)
            row.append(value or "-")
        else:
            row.append("-")
    return row

def build_trip_rows(cell_func):
    rows = []
    for trip in trips:
        if trip.trip_short_name not in ridership:
            continue
        rows.append(build_trip_row(trip, cell_func))
    return rows

def build_timetable(cell_func):
    return [[""]+header] + build_trip_rows(cell_func)

Timetable

In [10]:
def stop_time(stime, riders):
    return fmttime(stime.arrival_time or stime.departure_time)

make_table(transpose(build_timetable(stop_time)))
Out[10]:
102104206208210312314216218220322324226228230332134236138142146150152254156258360262264366268370272274376278380282284386288190192194196198
San Francisco4:55:005:25:006:06:006:24:006:44:006:56:007:12:007:19:007:24:007:44:007:56:008:12:008:19:008:24:008:44:008:56:009:00:009:37:0010:00:0011:00:0012:00:0013:00:0014:00:0014:37:0015:00:0015:37:0016:10:0016:19:0016:28:0016:33:0016:55:0017:12:0017:20:0017:28:0017:33:0017:55:0018:12:0018:20:0018:28:0018:33:0018:55:0019:33:0020:40:0021:40:0022:40:0024:01:00
22nd St5:00:005:30:006:11:006:29:006:50:007:02:007:18:007:25:007:29:007:50:008:02:008:18:008:25:008:29:008:50:009:02:009:05:00-10:05:0011:05:0012:05:0013:05:0014:05:00-15:05:00---16:33:00----17:33:00----18:33:00--19:38:0020:45:0021:45:0022:45:0024:06:00
Bayshore5:05:005:35:00-6:35:00----7:35:00----8:35:00--9:10:00-10:10:0011:10:0012:10:0013:10:0014:10:00-15:12:00---16:41:00----17:41:00----18:41:00--19:43:0020:50:0021:50:0022:50:0024:11:00
So. San Francisco5:11:005:41:00-6:41:00----7:41:00----8:41:00--9:15:00-10:15:0011:15:0012:15:0013:15:0014:15:00-15:17:00---16:49:00-17:08:00--17:49:00-18:08:00--18:49:00-19:08:0019:49:0020:56:0021:56:0022:56:0024:17:00
San Bruno5:15:005:45:00-6:44:00---7:37:007:44:00---8:37:008:44:00--9:18:009:52:0010:18:0011:18:0012:18:0013:18:0014:18:0014:52:0015:21:0015:52:00-16:33:0016:53:00---17:35:0017:53:00---18:35:0018:53:00--19:53:0021:00:0022:00:0023:00:0024:21:00
Millbrae5:19:005:49:006:24:006:49:007:02:007:17:007:32:00-7:49:008:02:008:17:008:32:00-8:49:009:02:009:17:009:22:009:56:0010:22:0011:22:0012:22:0013:22:0014:22:0014:56:0015:25:0015:56:0016:26:00-16:57:0016:50:0017:14:0017:30:00-17:57:0017:50:0018:14:0018:30:00-18:57:0018:50:0019:14:0019:57:0021:05:0022:05:0023:05:0024:25:00
Burlingame5:23:005:53:006:28:006:53:00---7:44:007:53:00---8:44:008:53:00--9:27:0010:01:0010:27:0011:27:0012:27:0013:27:0014:27:0015:01:0015:30:0016:01:00-16:38:0017:01:00---17:42:0018:01:00---18:42:0019:01:00--20:01:0021:09:0022:09:0023:09:0024:29:00
San Mateo5:28:005:58:006:32:006:56:007:09:00--7:48:007:56:008:09:00--8:48:008:56:009:09:00-9:30:0010:04:0010:30:0011:30:0012:30:0013:30:0014:30:0015:04:0015:33:0016:04:00-16:43:0017:06:0016:59:00--17:45:0018:06:0017:59:00--18:45:0019:06:0018:59:00-20:06:0021:13:0022:13:0023:13:0024:34:00
Hayward Park5:31:006:01:00-7:00:00----8:00:00----9:00:00--9:33:00-10:33:0011:33:0012:33:0013:33:0014:33:00-15:36:00---17:09:00----18:09:00----19:09:00--20:09:0021:16:0022:16:0023:16:0024:37:00
Hillsdale5:34:006:04:006:36:007:04:00--7:42:007:52:008:04:00--8:42:008:52:009:04:00--9:37:0010:08:0010:37:0011:37:0012:37:0013:37:0014:37:0015:08:0015:40:0016:08:0016:36:0016:48:0017:13:00-17:24:0017:40:0017:50:0018:13:00-18:24:0018:40:0018:50:0019:13:00-19:24:0020:12:0021:20:0022:20:0023:20:0024:40:00
Belmont5:37:006:07:00-7:07:00----8:07:00----9:07:00--9:41:0010:11:0010:41:0011:41:0012:41:0013:41:0014:41:0015:11:0015:44:0016:11:00--17:16:00----18:16:00----19:16:00--20:15:0021:24:0022:24:0023:24:0024:43:00
San Carlos5:40:006:10:006:40:007:11:007:16:00--7:58:008:11:008:16:00--8:58:009:11:009:16:00-9:44:0010:14:0010:44:0011:44:0012:44:0013:44:0014:44:0015:14:0015:47:0016:14:00-16:52:0017:20:00---17:55:0018:20:00---18:55:0019:20:00--20:18:0021:27:0022:27:0023:27:0024:46:00
Redwood City5:45:006:15:006:45:007:15:007:22:007:32:00--8:15:008:22:008:32:00--9:15:009:22:009:32:009:48:0010:20:0010:48:0011:48:0012:48:0013:48:0014:48:0015:20:0015:51:0016:20:00--17:24:0017:08:0017:30:00--18:24:0018:08:0018:30:00--19:24:0019:08:0019:30:0020:23:0021:31:0022:31:0023:31:0024:51:00
Menlo Park5:50:006:20:006:50:00-7:28:007:38:00-8:06:00-8:28:008:38:00-9:06:00-9:28:009:38:009:53:0010:26:0010:53:0011:53:0012:53:0013:53:0014:53:0015:26:0015:56:0016:26:00--17:30:00-17:36:00--18:30:00-18:36:00--19:30:00-19:36:0020:28:0021:36:0022:36:0023:36:0024:56:00
Palo Alto5:53:006:23:006:53:007:22:007:32:007:41:007:54:008:09:008:22:008:32:008:41:008:54:009:09:009:22:009:32:009:41:009:58:0010:30:0010:58:0011:58:0012:58:0013:58:0014:58:0015:30:0016:01:0016:30:0016:47:0017:02:00-17:16:0017:40:0017:52:0018:04:00-18:16:0018:40:0018:52:0019:04:00-19:16:0019:40:0020:31:0021:40:0022:40:0023:40:0024:59:00
California Ave5:57:006:27:006:57:00-7:35:00----8:35:00----9:35:00-10:01:0010:34:0011:01:0012:01:0013:01:0014:01:0015:01:0015:34:0016:04:0016:34:00-17:06:00--17:44:00-18:08:00--18:44:00-19:08:00--19:44:0020:35:0021:44:0022:44:0023:44:0025:03:00
San Antonio6:01:006:31:00--7:40:00----8:40:00----9:40:00-10:06:0010:38:0011:06:0012:06:0013:06:0014:06:0015:06:0015:38:0016:09:0016:38:00----17:48:00----18:48:00----19:48:0020:39:0021:48:0022:48:0023:48:0025:07:00
Mt View6:05:006:35:007:03:00-7:44:007:49:008:01:008:17:00-8:44:008:49:009:01:009:17:00-9:44:009:49:0010:10:0010:43:0011:10:0012:10:0013:10:0014:10:0015:10:0015:43:0016:13:0016:43:0016:54:0017:12:0017:38:00-17:52:0017:59:0018:14:0018:38:00-18:52:0018:59:0019:14:0019:38:00-19:52:0020:43:0021:52:0022:52:0023:52:0025:11:00
Sunnyvale6:10:006:40:00--7:49:00----8:49:00----9:49:00-10:15:0010:48:0011:15:0012:15:0013:15:0014:15:0015:15:0015:48:0016:18:0016:48:00-17:17:0017:43:0017:26:0017:57:00-18:20:0018:43:0018:26:0018:57:00-19:20:0019:43:0019:26:0019:57:0020:48:0021:57:0022:57:0023:57:0025:16:00
Lawrence6:14:006:44:007:08:00-7:55:00--8:24:00-8:55:00--9:24:00-9:55:00-10:20:0010:52:0011:20:0012:20:0013:20:0014:20:0015:20:0015:52:0016:23:0016:52:00----18:03:00--18:47:00-19:03:00----20:03:0020:52:0022:01:0023:01:0024:01:0025:20:00
Santa Clara6:19:006:49:00-7:36:008:02:00---8:36:009:02:00---9:36:0010:02:00-10:25:0010:57:0011:25:0012:25:0013:25:0014:25:0015:25:0015:57:0016:28:0016:57:00--17:52:00-18:10:00--18:52:00-19:10:00--19:52:00-20:10:0020:57:0022:06:0023:06:0024:06:0025:25:00
College Park----8:05:00-------------------16:32:00---------------------
San Jose Diridon6:28:006:58:007:20:007:45:008:11:008:03:008:16:008:34:008:45:009:10:009:03:009:16:009:34:009:45:0010:10:0010:03:0010:34:0011:04:0011:34:0012:34:0013:34:0014:34:0015:34:0016:04:0016:38:0017:04:0017:09:0017:28:0018:00:0017:36:0018:20:0018:14:0018:30:0019:00:0018:36:0019:20:0019:14:0019:30:0020:00:0019:36:0020:18:0021:06:0022:13:0023:13:0024:13:0025:34:00
Tamien-7:05:00-7:52:008:18:00---8:52:009:17:00---9:52:0010:17:00--11:11:00-----16:11:0016:45:0017:11:00---17:43:0018:26:00--19:06:0018:43:0019:26:00---19:43:0020:25:00-22:20:0023:20:00--
Capitol------------------------16:52:00-----18:33:00--19:13:00------------
Blossom Hill------------------------16:58:00-----18:39:00--19:19:00------------
Morgan Hill------------------------17:11:00-----18:52:00--19:32:00------------
San Martin------------------------17:17:00-----18:58:00--19:38:00------------
Gilroy------------------------17:30:00-----19:11:00--19:51:00------------

Boardings

In [11]:
def boardings(stime, riders): return round(riders["boardings"])

make_table(transpose(build_timetable(boardings)))
Out[11]:
102104206208210312314216218220322324226228230332134236138142146150152254156258360262264366268370272274376278380282284386288190192194196198
San Francisco1724112331812193061618342539735719314236936715425418817915116917519215827749039410961861479172722588678069752313660455942940724217183
22nd St795717961171446425140144143793314214355-4522181112-11---21----30----20--171910127
Bayshore44-19----36----31--22-128988-11---13----8----5--44321
So. San Francisco68-9----20----15--9-655610-20---40-44--33-18--11-764331
San Bruno68-26---5529---3318--17101551191381015-1417---3012---198--55532
Millbrae836845983157115-89115129117-7290787459706648646343837987-881036779-921108253-6162436843352615
Burlingame4112224---6647---4035--25121212911991211-1924---2513---159--98631
San Mateo7193226131--693182--642250-26191913181515135925-233442--443060--271422-17151576
Hayward Park310-21----26----18--8-736811-13---36----19----7--25211
Hillsdale8103739--1146956--883737--3210121216131298014472880-37333046-43301518-12141252-
Belmont68-34----58----35--159888686147--31----24----10--8751-
San Carlos87242946--653442--392424-131911679891826-3665---5027---1911--65531
Redwood City101522353944--505754--32372527571718181522285479--12414782--7911250--31302521221651
Menlo Park4616-3812-31-2014-18-1513851011171419146856--115-60--66-21--13-16109421
Palo Alto6513203482614135311181864061211151724466779232195195188-31924614489-1431214441-4380513717104
California Ave148-19----17----11-244691117134435-85--88-46--33-15--23141032-
San Antonio32--18----10----8-31246746229----38----23----754111
Mt View417-226810-51148-57444461110146435234353-47272734-11121410-812522-
Sunnyvale13--19----8----4-112333883113-22203135-1212287-44375221-
Lawrence1-1-6--4-3--10-2-1-123343458----46--7-4-----22---
Santa Clara---61---21---11-1--11-12163--4-17--3-2--2--11---
College Park------------------------32---------------------
San Jose Diridon-----------------------524----4380--6815---4--2---
Tamien------------------------7-----5--3------------
Capitol------------------------3---------------------
Blossom Hill------------------------3-----1---------------
Morgan Hill----------------------------------------------
San Martin----------------------------------------------
Gilroy----------------------------------------------

Alightings

In [12]:
def alightings(stime, riders): return round(riders["alightings"])

make_table(transpose(build_timetable(alightings)))
Out[12]:
102104206208210312314216218220322324226228230332134236138142146150152254156258360262264366268370272274376278380282284386288190192194196198
San Francisco----------------------------------------------
22nd St--1--31-2312--213-1-----1---3----2----1--11-1-
Bayshore--------2----3--1----1--1---2----11----9--622--
So. San Francisco-3-4----19----32--11-52334-10---12-13--15-16--10-776322
San Bruno-1-1---83---214--33545847511-3212---7012---427--1517712
Millbrae21445811-81667-9121253547451061718-5363141-9695044-943352317951
Burlingame-213---1711---1912--1712125912991315-3220---9830---8326--38161385
San Mateo1251113--201553--532556-31241818121727151826-541444--1222291--1041472-452913118
Hayward Park-4-9----20----24--22-118565-6---17----28----18--811534
Hillsdale111311--763130--622331--27181715151923252836954748-1541497450-1831446037-110474123137
Belmont14-12----27----15--1261188111191419--26----48----28--2113763
San Carlos23221829--431638--261951-20121810111212112119-4220---9320---7513--221111104
Redwood City1014365048119--7375153--757712648435538373643354444--5012088--33205124--25139795047292015
Menlo Park4927-11459-59-7465-51-433918313318201318103423--45-64--30-78--21-4123191692
Palo Alto285913118713414532017326620924433613320316722512313694947058504258409935-787512963-1589112838-89654347342510
California Ave6922-62----178----135-41392118121716142722-45--74-59--74-47--39252718105
San Antonio38--35----61----49-12191412182217162433----119----111----61222515114
Mt View142085-83146217120-128210254118-1031895950384240394337817920296134-150295106100-1122656149-978587513612
Sunnyvale716--53----77----54-171721252433484886108-229105339173-24272345156-11729210957472422311
Lawrence3635-28--92-31--70-20-101212810919144040----97--41-61----3625221165
Santa Clara119-4013---5414---4012-13141722202433326782--147-77--85-59--40-29252314137
College Park----101-------------------31---------------------
San Jose Diridon231354431183874751198166222617482034515465941098114917642924121435064459153833035325563361347010175504119
Tamien-6-33---11---4---2-----4579100---33696--2217543---8124-219--
Capitol------------------------17-----29--10------------
Blossom Hill------------------------50-----50--9------------
Morgan Hill------------------------82-----66--15------------
San Martin------------------------39-----27--2------------
Gilroy------------------------99-----62--16------------

Boardings and alightings

In [13]:
def boardings_and_alightings(stime, riders):
    return "+%d/-%d" % (round(riders["boardings"]), round(riders["alightings"]))

make_table(transpose(build_timetable(boardings_and_alightings)))
Out[13]:
102104206208210312314216218220322324226228230332134236138142146150152254156258360262264366268370272274376278380282284386288190192194196198
San Francisco+17/-0+24/-0+112/-0+33/-0+181/-0+219/-0+306/-0+161/-0+83/-0+425/-0+397/-0+357/-0+193/-0+142/-0+369/-0+367/-0+154/-0+254/-0+188/-0+179/-0+151/-0+169/-0+175/-0+192/-0+158/-0+277/-0+490/-0+394/-0+109/-0+618/-0+614/-0+791/-0+727/-0+225/-0+886/-0+780/-0+697/-0+523/-0+136/-0+604/-0+559/-0+429/-0+407/-0+242/-0+171/-0+83/-0
22nd St+7/-0+9/-0+57/-1+17/-0+96/-0+117/-3+144/-1+64/-0+25/-2+140/-3+144/-1+143/-2+79/-0+33/-0+142/-2+143/-1+55/-3-+45/-1+22/-0+18/-0+11/-0+12/-0-+11/-1---+21/-3----+30/-2----+20/-1--+17/-1+19/-1+10/-0+12/-1+7/-0
Bayshore+4/-0+4/-0-+19/-0----+36/-2----+31/-3--+22/-1-+12/-0+8/-0+9/-0+8/-1+8/-0-+11/-1---+13/-2----+8/-11----+5/-9--+4/-6+4/-2+3/-2+2/-0+1/-0
So. San Francisco+6/-0+8/-3-+9/-4----+20/-19----+15/-32--+9/-11-+6/-5+5/-2+5/-3+6/-3+10/-4-+20/-10---+40/-12-+44/-13--+33/-15-+18/-16--+11/-10-+7/-7+6/-7+4/-6+3/-3+3/-2+1/-2
San Bruno+6/-0+8/-1-+26/-1---+55/-8+29/-3---+33/-21+18/-4--+17/-3+10/-3+15/-5+5/-4+11/-5+9/-8+13/-4+8/-7+10/-5+15/-11-+14/-32+17/-12---+30/-70+12/-12---+19/-42+8/-7--+5/-15+5/-17+5/-7+3/-1+2/-2
Millbrae+8/-2+36/-1+84/-4+59/-4+83/-5+157/-8+115/-11-+89/-8+115/-16+129/-6+117/-7-+72/-9+90/-12+78/-12+74/-5+59/-3+70/-5+66/-4+48/-7+64/-4+63/-5+43/-10+83/-6+79/-17+87/-18-+88/-5+103/-36+67/-31+79/-41-+92/-9+110/-69+82/-50+53/-44-+61/-9+62/-43+43/-35+68/-23+43/-17+35/-9+26/-5+15/-1
Burlingame+4/-0+11/-2+22/-1+24/-3---+66/-17+47/-11---+40/-19+35/-12--+25/-17+12/-12+12/-12+12/-5+9/-9+11/-12+9/-9+9/-9+12/-13+11/-15-+19/-32+24/-20---+25/-98+13/-30---+15/-83+9/-26--+9/-38+8/-16+6/-13+3/-8+1/-5
San Mateo+7/-1+19/-2+32/-5+26/-11+131/-13--+69/-20+31/-15+82/-53--+64/-53+22/-25+50/-56-+26/-31+19/-24+19/-18+13/-18+18/-12+15/-17+15/-27+13/-15+59/-18+25/-26-+23/-54+34/-14+42/-44--+44/-122+30/-22+60/-91--+27/-104+14/-14+22/-72-+17/-45+15/-29+15/-13+7/-11+6/-8
Hayward Park+3/-0+10/-4-+21/-9----+26/-20----+18/-24--+8/-22-+7/-11+3/-8+6/-5+8/-6+11/-5-+13/-6---+36/-17----+19/-28----+7/-18--+2/-8+5/-11+2/-5+1/-3+1/-4
Hillsdale+8/-1+10/-1+37/-13+39/-11--+114/-76+69/-31+56/-30--+88/-62+37/-23+37/-31--+32/-27+10/-18+12/-17+12/-15+16/-15+13/-19+12/-23+9/-25+80/-28+14/-36+47/-95+28/-47+80/-48-+37/-154+33/-149+30/-74+46/-50-+43/-183+30/-144+15/-60+18/-37-+12/-110+14/-47+12/-41+5/-23+2/-13+0/-7
Belmont+6/-1+8/-4-+34/-12----+58/-27----+35/-15--+15/-12+9/-6+8/-11+8/-8+8/-8+6/-11+8/-11+6/-9+14/-14+7/-19--+31/-26----+24/-48----+10/-28--+8/-21+7/-13+5/-7+1/-6+0/-3
San Carlos+8/-2+7/-3+24/-22+29/-18+46/-29--+65/-43+34/-16+42/-38--+39/-26+24/-19+24/-51-+13/-20+19/-12+11/-18+6/-10+7/-11+9/-12+8/-12+9/-11+18/-21+26/-19-+36/-42+65/-20---+50/-93+27/-20---+19/-75+11/-13--+6/-22+5/-11+5/-11+3/-10+1/-4
Redwood City+10/-10+15/-14+22/-36+35/-50+39/-48+44/-119--+50/-73+57/-75+54/-153--+32/-75+37/-77+25/-126+27/-48+57/-43+17/-55+18/-38+18/-37+15/-36+22/-43+28/-35+54/-44+79/-44--+124/-50+147/-120+82/-88--+79/-33+112/-205+50/-124--+31/-25+30/-139+25/-79+21/-50+22/-47+16/-29+5/-20+1/-15
Menlo Park+4/-4+6/-9+16/-27-+38/-114+12/-59-+31/-59-+20/-74+14/-65-+18/-51-+15/-43+13/-39+8/-18+5/-31+10/-33+11/-18+17/-20+14/-13+19/-18+14/-10+68/-34+56/-23--+115/-45-+60/-64--+66/-30-+21/-78--+13/-21-+16/-41+10/-23+9/-19+4/-16+2/-9+1/-2
Palo Alto+6/-28+5/-59+13/-131+20/-187+34/-134+8/-145+26/-320+14/-173+13/-266+53/-209+11/-244+18/-336+18/-133+6/-203+40/-167+6/-225+12/-123+11/-136+15/-94+17/-94+24/-70+46/-58+67/-50+79/-42+232/-58+195/-40+195/-99+188/-35-+319/-78+246/-75+144/-129+89/-63-+143/-158+121/-91+44/-128+41/-38-+43/-89+80/-65+51/-43+37/-47+17/-34+10/-25+4/-10
California Ave+1/-6+4/-9+8/-22-+19/-62----+17/-178----+11/-135-+2/-41+4/-39+4/-21+6/-18+9/-12+11/-17+17/-16+13/-14+44/-27+35/-22-+85/-45--+88/-74-+46/-59--+33/-74-+15/-47--+23/-39+14/-25+10/-27+3/-18+2/-10+0/-5
San Antonio+3/-3+2/-8--+18/-35----+10/-61----+8/-49-+3/-12+1/-19+2/-14+4/-12+6/-18+7/-22+4/-17+6/-16+22/-24+9/-33----+38/-119----+23/-111----+7/-61+5/-22+4/-25+1/-15+1/-11+1/-4
Mt View+4/-14+1/-20+7/-85-+22/-83+6/-146+8/-217+10/-120-+5/-128+11/-210+4/-254+8/-118-+5/-103+7/-189+4/-59+4/-50+4/-38+4/-42+6/-40+11/-39+10/-43+14/-37+64/-81+35/-79+23/-202+43/-96+53/-134-+47/-150+27/-295+27/-106+34/-100-+11/-112+12/-265+14/-61+10/-49-+8/-97+12/-85+5/-87+2/-51+2/-36+0/-12
Sunnyvale+1/-7+3/-16--+19/-53----+8/-77----+4/-54-+1/-17+1/-17+2/-21+3/-25+3/-24+3/-33+8/-48+8/-48+31/-86+13/-108-+22/-229+20/-105+31/-339+35/-173-+12/-242+12/-72+28/-345+7/-156-+4/-117+4/-29+3/-210+7/-95+5/-74+2/-72+2/-42+1/-23+0/-11
Lawrence+1/-3+0/-6+1/-35-+6/-28--+4/-92-+3/-31--+10/-70-+2/-20-+1/-10+0/-12+1/-12+2/-8+3/-10+3/-9+4/-19+3/-14+45/-40+8/-40----+46/-97--+7/-41-+4/-61----+0/-36+2/-25+2/-22+0/-11+0/-6+0/-5
Santa Clara+0/-11+0/-9-+6/-40+1/-13---+2/-54+1/-14---+1/-40+1/-12-+1/-13+0/-14+0/-17+1/-22+1/-20+0/-24+1/-33+2/-32+16/-67+3/-82--+4/-147-+17/-77--+3/-85-+2/-59--+2/-40-+0/-29+1/-25+1/-23+0/-14+0/-13+0/-7
College Park----+0/-101-------------------+32/-31---------------------
San Jose Diridon+0/-23+0/-13+0/-54+0/-43+0/-11+0/-83+0/-87+0/-47+0/-51+0/-19+0/-81+0/-66+0/-22+0/-26+0/-17+0/-48+0/-20+0/-34+0/-51+0/-54+0/-65+0/-94+0/-109+5/-81+24/-149+0/-176+0/-429+0/-241+0/-214+43/-350+80/-64+0/-459+0/-153+6/-83+8/-303+15/-53+0/-255+0/-63+0/-36+4/-134+0/-70+0/-101+2/-75+0/-50+0/-41+0/-19
Tamien-+0/-6-+0/-3+0/-3---+0/-1+0/-1---+0/-4+0/-0--+0/-2-----+0/-45+7/-79+0/-100---+0/-336+5/-96--+3/-22+0/-175+0/-43---+0/-81+0/-24-+0/-21+0/-9--
Capitol------------------------+3/-17-----+0/-29--+0/-10------------
Blossom Hill------------------------+3/-50-----+1/-50--+0/-9------------
Morgan Hill------------------------+0/-82-----+0/-66--+0/-15------------
San Martin------------------------+0/-39-----+0/-27--+0/-2------------
Gilroy------------------------+0/-99-----+0/-62--+0/-16------------

Onboard

In [14]:
def onboard(stime, riders): return round(riders["onboard"])

make_table(transpose(build_timetable(onboard)))
Out[14]:
102104206208210312314216218220322324226228230332134236138142146150152254156258360262264366268370272274376278380282284386288190192194196198
San Francisco1724112331812193061618342539735719314236936715425418817915116917519215827749039410961861479172722588678069752313660455942940724217183
22nd St243316850277333449225107562540498271175508509207-231201169180187-167---128----252----155--44542625218290
Bayshore2837-69----140----204--228-243208178187194-177---139----250----151--44442825318390
So. San Francisco3443-74----142----187--226-244211180189201-187---166-645--267-783--152-55844242625218489
San Bruno4050-99---273168---283201--240261255212185190210192192281-376172---687267---500154--43341425018689
Millbrae4684248153355482553-249662663608-264586575309318320274226250268225269344559-254685680829-350927814705-205623566478440276207103
Burlingame5093269174---321284---304287--318317320280226248268226268340-363258---614333---432188--44943226920199
San Mateo56111296189473--371300691--315283580-313312320276232246256225309339-333278682--535341896--355189573-42141827119797
Hayward Park59116-201----306----278--299-316272234248262-316---297----332----179--41541226819494
Hillsdale66126320229--591409332--633329283--304304312269235242250207368318512314330-564713490328-674591309160-46938238325018387
Belmont72129-251----363----303--307307309269234237247204368306--335----304----143--36937724917885
San Carlos78133323262489--432381694--341309554-301314302265230234244202365313-308380---447311---253141--35337124317181
Redwood City78133309246480407--358676564--266514474280327264245211213223194375347--453710558--357803601--14746441532434623015768
Menlo Park78131298-404360-404-622513-308-486449270302241238208214223199408380--524-555--393-544--138-39131133621915066
Palo Alto56761807930422429624610546628031619368359230159176162161162202241236582535608461-950725727473-788574508256-41840631932720213561
California Ave5271165-261----306----235-120141145149159196242235599548-501--740-461--533-224--38930831018712756
San Antonio5265--244----255----194-111123133141147181229225597524----660----445----33529028917311653
Mt View424687-1838387136-131816683-9648577899104113153196202580480429448443-557459382326-34425517699-2462182071248241
Sunnyvale3632--149----62----46-4162798191124156162525386-241358643419-153266470195-6374211158148137846030
Lawrence332754-127--47-34--22-28-3251687584118141151530354----367--231-138----122125116735426
Santa Clara2319-46115---5320---3017-203751546594109121478276--214-308--149-81--36-9410194594119
College Park----13-------------------479---------------------
San Jose Diridon-6-33---11---4---2-----45354100---336323--7217543---8124-219--
Tamien------------------------282-----232--52------------
Capitol------------------------267-----204--42------------
Blossom Hill------------------------220-----155--33------------
Morgan Hill------------------------138-----89--18------------
San Martin------------------------99-----62--16------------
Gilroy----------------------------------------------

Did you enjoy this post? Let me know on twitter. Also, Remix is hiring.