Exploring Bay Area bike-share patterns with Bay Wheel open data
Baywheel.ing visualizes BayWheels trip patterns using anonymized historical system data published by Lyft.
Click any station to view stats. Browse different months to spot seasonal patterns.
Rides Data:
- Historical trip data is stored in D1 partitioned by month (
rides_YYYYMMtables) - Each ride includes start/end stations, times, and (once computed) cached route polylines
Route Polylines:
- OSRM API computes cycling routes between stations on-demand
- Computed routes are cached in D1 (per-ride) and KV (per route pair) to avoid redundant API calls
- Routes are grouped by origin→destination pair; if multiple rides share the same route, the line thickness increases by
1 + log(rideCount) * 0.1for subtle visual emphasis
Station Stats:
- Aggregated stats (top destinations, busiest hours, etc.) are streamed as JSON-lines and cached in KV to avoid expensive re-aggregation
OSRM enforces a 1 request/second limit per IP. To respect this:
- Client initiates requests with a 2 concurrent limit
- Requests are staggered by 500ms (queueIndex * 500) to maintain spacing
- Combined with Cloudflare's caching, this prevents bandwidth blocks
Route lines are computed using OSRM, the only free open-source routing engine I could find.
It only supports driving and walking modes. Cycling is used here.
If you have another free and simple option, feel free to open an issue.
- Next.js with shadcn/ui and Tailwind
- MapLibre GL (via mapcn and carto) for mapping
- Deck.gl for route rendering
- Recharts for charts
- Cloudflare Workers — Edge compute for OSRM routing requests and API proxying
- Cloudflare D1 — SQLite database for caching computed route polylines, reducing API calls to OSRM
- Cloudflare KV — Key-value store for rapid access to station metadata and frequently-requested aggregated trip statistics
- Cloudflare via opennext for hosting
- Node.js 18+ and pnpm
- Cloudflare account with D1 and KV enabled
-
Clone and install:
git clone https://github.com/samwarnick/baywheeling cd baywheeling pnpm install pnpm run init -
Run the development server:
pnpm dev
Open http://localhost:3000 in your browser.
-
Deploying to Cloudflare (optional):
pnpm deploy
This builds and deploys to Cloudflare Pages, Workers, D1, and KV using the bindings configured in
wrangler.jsonc.
Note
The app relies on historical trip data from Lyft's Bay Wheels system. This data is not included in the repository due to size, but you can easily load it yourself using the steps below.
Make you run the init script before loading data, as it sets up the D1 database. KV should just work without initialization, but D1 needs the schema to be created first.
To load Bay Wheels trip data into D1:
-
Download system data: Download CSV files from Lyft's Bay Wheels system data and place them in
utils/data/:utils/data/202512-baywheels-tripdata.csv utils/data/202601-baywheels-tripdata.csv # etc. -
Convert CSV to SQL:
python utils/csv_to_d1_sql.py utils/data
This generates SQL insert statements from the CSV files.
-
Upload to D1:
./utils/load-seeds.sh
This loads the generated SQL into your Cloudflare D1 database.