diff --git a/docs/blog/septa-timetables/chw-stops.csv b/docs/blog/septa-timetables/chw-stops.csv new file mode 100644 index 000000000..d9fedd5d9 --- /dev/null +++ b/docs/blog/septa-timetables/chw-stops.csv @@ -0,0 +1,15 @@ +service_access,service_cash,service_park,fare_zone,stop_id,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url +1,0,1,2,90004,Gray 30th Street,,39.9566667,-75.1816667,CC, +0,0,1,2,90005,Suburban Station,,39.9538889,-75.1677778,CC, +0,0,1,2,90006,Jefferson Station,,39.9525,-75.1580556,CC, +1,0,1,2,90007,Temple University,,39.9813889,-75.1494444,CC, +0,0,1,2,90801,Chestnut Hill West,,40.0763889,-75.2083333,2S, +0,0,1,2,90802,Highland,,40.0705556,-75.2111111,2S, +0,0,1,1,90803,St. Martins,,40.0658333,-75.2044444,2S, +0,0,1,1,90804,Richard Allen Lane,,40.0575,-75.1947222,2S, +1,0,1,1,90805,Carpenter,,40.0511111,-75.1913889,2S, +0,0,0,1,90806,Upsal,,40.0425,-75.19,2S, +1,1,0,C,90807,Tulpehocken,,40.0352778,-75.1869444,2S, +1,1,0,C,90808,Chelten Avenue,,40.03,-75.1808333,1S, +1,1,0,C,90809,Queen Lane,,40.0233333,-75.1780556,1S, +1,0,0,C,90810,North Philadelphia,,39.9977778,-75.1563889,1S, diff --git a/docs/blog/septa-timetables/example-timetable.png b/docs/blog/septa-timetables/example-timetable.png new file mode 100644 index 000000000..196ee7bb6 Binary files /dev/null and b/docs/blog/septa-timetables/example-timetable.png differ diff --git a/docs/blog/septa-timetables/index.qmd b/docs/blog/septa-timetables/index.qmd new file mode 100644 index 000000000..5cddf91bb --- /dev/null +++ b/docs/blog/septa-timetables/index.qmd @@ -0,0 +1,105 @@ +--- +title: Recreating Septa Transit Timetables in Python +format: html +html-table-processing: none +--- + + +```{python} +import polars as pl + +stops = pl.read_csv("chw-stops.csv") +times = pl.read_csv("times.csv") +``` + + +```{python} +stop_times = times.join(other=stops, on="stop_name", maintain_order="left") + + +stop_times +``` + + +```{python} +from great_tables import GT, html, style, loc, google_font +import polars as pl +import polars.selectors as cs + + +def h_m_p(s): + h, m, _ = [int(part) for part in s.split(":")] + ap = "a" + + if h > 12: + h -= 12 + ap = "p" + return f"{h}:{m:02d}{ap}" + +def tick(b): + return "✓" if b else "" + +transit_table = ( + GT(stop_times) + .cols_hide(columns=["stop_url", "zone_id", "stop_desc", "stop_lat", "stop_lon", "stop_id"]) + .fmt(h_m_p, columns=cs.matches(r"^[0-9]{4}$")) + .fmt(tick, columns=cs.starts_with("service_")) + .cols_label( + stop_name="Stations", + service_access="A", + service_cash="C", + service_park="P", + fare_zone=html("Fare
Zone") + ) + .tab_spanner( + label="Services", + columns=cs.starts_with("service_") + ) + .tab_spanner( + label="Train Number", + columns=cs.matches(r"^[0-9]{4}$") + ) + .cols_move_to_start("fare_zone") + .cols_move_to_start(cs.starts_with("service_")) + .cols_width( + cases={c:"20px" for c in stop_times.columns if c.startswith("service_")} + ) + .cols_width( + cases={c:"80px" for c in stop_times.columns if c.startswith("8")} + ) + .opt_row_striping(row_striping=True) + .cols_align(align="center", columns="fare_zone") + .cols_align(align="right", columns=cs.matches(r"^[0-9]{4}$")) + + .tab_style( + style= style.css("background-color: black !important; color: white !important; border-top: none !important; border-bottom: none !important;"), + locations=loc.body(columns=None, rows=list(range(-4, -1)) + ) + ) + .tab_style( + style= style.css( + """ + border-top: none !important; + border-bottom: none !important; + border-right: solid white 2px !important; + color: white !important; + """ + ), + locations=loc.body(columns=~cs.matches(r"^[0-9]{4}$"), rows=list(range(-4, -1)) + ) + ) + .tab_style( + style= style.css("border-right: solid black 2px !important;"), + locations=loc.body( + columns=~cs.matches(r"^[0-9]{4}$"), + rows=list(range(0, 10)) + [13] + ) + ) + .tab_options(row_striping_background_color="#A9A9A9") + .opt_table_font(font=google_font("IBM Plex Sans")) +) + +transit_table +``` + + diff --git a/docs/blog/septa-timetables/stops-times.csv b/docs/blog/septa-timetables/stops-times.csv new file mode 100644 index 000000000..2eb1c8728 --- /dev/null +++ b/docs/blog/septa-timetables/stops-times.csv @@ -0,0 +1,15 @@ +service_access,service_cash,service_park,fare_zone,stop_id,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,8210,8242,8318,8322,8338,8716,8750,8756 +1,0,1,2,90004,Gray 30th Street,,39.9566667,-75.1816667,CC,,07:23:00,15:23:00,09:23:00,10:23:00,14:26:00,08:42:00,17:20:00,18:54:00 +0,0,1,2,90005,Suburban Station,,39.9538889,-75.1677778,CC,,07:28:00,15:28:00,09:28:00,10:28:00,14:31:00,08:47:00,17:25:00,18:59:00 +0,0,1,2,90006,Jefferson Station,,39.9525,-75.1580556,CC,,07:33:00,15:33:00,09:33:00,10:33:00,14:36:00,08:52:00,17:30:00,19:04:00 +1,0,1,2,90007,Temple University,,39.9813889,-75.1494444,CC,,07:37:00,15:37:00,09:37:00,10:37:00,14:40:00,08:57:00,17:35:00,19:08:00 +0,0,1,2,90801,Chestnut Hill West,,40.0763889,-75.2083333,2S,,06:51:00,14:49:00,08:49:00,09:49:00,13:52:00,08:08:00,16:48:00,18:20:00 +0,0,1,2,90802,Highland,,40.0705556,-75.2111111,2S,,06:52:00,14:50:00,08:50:00,09:50:00,13:53:00,08:09:00,16:49:00,18:21:00 +0,0,1,1,90803,St. Martins,,40.0658333,-75.2044444,2S,,06:54:00,14:52:00,08:52:00,09:52:00,13:55:00,08:11:00,16:51:00,18:23:00 +0,0,1,1,90804,Richard Allen Lane,,40.0575,-75.1947222,2S,,06:56:00,14:54:00,08:54:00,09:54:00,13:57:00,08:13:00,16:53:00,18:25:00 +1,0,1,1,90805,Carpenter,,40.0511111,-75.1913889,2S,,06:58:00,14:56:00,08:56:00,09:56:00,13:59:00,08:15:00,16:55:00,18:27:00 +0,0,0,1,90806,Upsal,,40.0425,-75.19,2S,,07:00:00,14:58:00,08:58:00,09:58:00,14:01:00,08:17:00,16:57:00,18:29:00 +1,1,0,C,90807,Tulpehocken,,40.0352778,-75.1869444,2S,,07:02:00,15:00:00,09:00:00,10:00:00,14:03:00,08:19:00,16:59:00,18:31:00 +1,1,0,C,90808,Chelten Avenue,,40.03,-75.1808333,1S,,07:04:00,15:02:00,09:02:00,10:02:00,14:05:00,08:21:00,17:01:00,18:33:00 +1,1,0,C,90809,Queen Lane,,40.0233333,-75.1780556,1S,,07:06:00,15:04:00,09:04:00,10:04:00,14:07:00,08:23:00,17:03:00,18:35:00 +1,0,0,C,90810,North Philadelphia,,39.9977778,-75.1563889,1S,,07:12:00,15:12:00,09:12:00,10:12:00,14:15:00,08:29:00,17:09:00,18:41:00 diff --git a/docs/blog/septa-timetables/times.csv b/docs/blog/septa-timetables/times.csv new file mode 100644 index 000000000..d2029b30c --- /dev/null +++ b/docs/blog/septa-timetables/times.csv @@ -0,0 +1,15 @@ +stop_name,8210,8242,8318,8322,8338,8716,8750,8756 +Chestnut Hill West,06:51:00,14:49:00,08:49:00,09:49:00,13:52:00,08:08:00,16:48:00,18:20:00 +Highland,06:52:00,14:50:00,08:50:00,09:50:00,13:53:00,08:09:00,16:49:00,18:21:00 +St. Martins,06:54:00,14:52:00,08:52:00,09:52:00,13:55:00,08:11:00,16:51:00,18:23:00 +Richard Allen Lane,06:56:00,14:54:00,08:54:00,09:54:00,13:57:00,08:13:00,16:53:00,18:25:00 +Carpenter,06:58:00,14:56:00,08:56:00,09:56:00,13:59:00,08:15:00,16:55:00,18:27:00 +Upsal,07:00:00,14:58:00,08:58:00,09:58:00,14:01:00,08:17:00,16:57:00,18:29:00 +Tulpehocken,07:02:00,15:00:00,09:00:00,10:00:00,14:03:00,08:19:00,16:59:00,18:31:00 +Chelten Avenue,07:04:00,15:02:00,09:02:00,10:02:00,14:05:00,08:21:00,17:01:00,18:33:00 +Queen Lane,07:06:00,15:04:00,09:04:00,10:04:00,14:07:00,08:23:00,17:03:00,18:35:00 +North Philadelphia,07:12:00,15:12:00,09:12:00,10:12:00,14:15:00,08:29:00,17:09:00,18:41:00 +Gray 30th Street,07:23:00,15:23:00,09:23:00,10:23:00,14:26:00,08:42:00,17:20:00,18:54:00 +Suburban Station,07:28:00,15:28:00,09:28:00,10:28:00,14:31:00,08:47:00,17:25:00,18:59:00 +Jefferson Station,07:33:00,15:33:00,09:33:00,10:33:00,14:36:00,08:52:00,17:30:00,19:04:00 +Temple University,07:37:00,15:37:00,09:37:00,10:37:00,14:40:00,08:57:00,17:35:00,19:08:00