Skip to content

Commit

Permalink
wow it work
Browse files Browse the repository at this point in the history
  • Loading branch information
nate-parrott committed Dec 7, 2017
1 parent 63c960a commit f75e14a
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 9 deletions.
1 change: 1 addition & 0 deletions gtfs_json.js

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions gtfs_json.py
@@ -0,0 +1,63 @@
import json
import csv
from collections import defaultdict
import os

HOURS = 60 * 60

def gtfs_json(gtfs_path, included_service_groups=[], min_time=0, max_time=48*HOURS):
def read_csv(name):
return list(csv.DictReader(open(os.path.join(gtfs_path, name + '.txt'))))

parent_stops = {}
for stop in read_csv('stops'):
if stop['parent_station']:
parent_stops[stop['stop_id']] = stop['parent_station']
def resolve_stop_id(stop_id):
return parent_stops.get(stop_id, stop_id)

transfers = defaultdict(list)
for transfer in read_csv('transfers'):
if transfer['transfer_type'] != '3': # 3 is 'no transfers'
from_stop_id = resolve_stop_id(transfer['from_stop_id'])
to_stop_id = resolve_stop_id(transfer['to_stop_id'])
transfers[from_stop_id].append({"to": to_stop_id, "time": float(transfer['min_transfer_time'] or "0")})

routes_by_id = {route['route_id']: route for route in read_csv('routes')}
trips_by_id = {trip['trip_id']: trip for trip in read_csv('trips')}
stop_times = read_csv('stop_times')

service_groups = {
'saturday': ['A20171105SAT', 'B20171105SAT'],
'sunday': ['A20171105SUN', 'B20171105SUN'],
'weekdays': ['A20171105WKD', 'B20171105WKD']
}

events_by_service_group = {}
for service_group, service_ids in service_groups.items():
if service_group in included_service_groups:
events = []
for stop_time in stop_times:
trip = trips_by_id[stop_time['trip_id']]
route = routes_by_id[trip['route_id']]
if trip['service_id'] in service_ids:
time = time_str_to_float(stop_time['departure_time'])
if time >= min_time and time <= max_time:
stop_id = resolve_stop_id(stop_time['stop_id'])
events.append({"time": time, "trip_id": stop_time['trip_id'], "stop_id": stop_id, "route_name": route['route_short_name']})
events.sort(key=lambda x: x['time'])
events_by_service_group[service_group] = events
return {
"transfers": transfers,
"events_by_service_group": events_by_service_group
}

def time_str_to_float(t): # in seconds
parts = t.split(':')
hours, mins, secs = map(float, parts)
return hours * 60 * 60 + mins * 60 + secs
assert time_str_to_float('01:23:00') == 1 * 60 * 60 + 23 * 60

if __name__ == '__main__':
j = gtfs_json('google_transit', ['weekdays'], 8*HOURS, 11*HOURS)
open('gtfs_json.js', 'w').write('gtfs_json = ' + json.dumps(j))
16 changes: 9 additions & 7 deletions index.html
Expand Up @@ -14,9 +14,9 @@
}
</style>
<script src="subway.js"></script>
<script src="routing_graph.js"></script>
<script src="gtfs_json.js"></script>
<script src="https://unpkg.com/js-heap@0.3.1/heap.js"></script>
<script src="routing.js"></script>
<script src="virtual_rider.js"></script>
</head>
<body>
<script>
Expand All @@ -29,7 +29,7 @@
let computeStationPositions = (originStationId) => {
let originLat = stations[originStationId].lat;
let originLon = stations[originStationId].lon;
let travelTimes = travelTimesToAllStations(originStationId);
let travelTimes = computeTravelTimes(originStationId, Object.keys(stations), gtfs_json, 8 * 60 * 60, 'weekdays');

let maxTravelTime = 70 * 60;

Expand All @@ -39,18 +39,19 @@

let deltaY = lat - originLat;
let deltaX = (lon - originLon) * 0.767;
let angle = Math.atan2(deltaY, deltaX);
let angle = Math.atan2(deltaY, deltaX) + 30 / 180 * Math.PI;
let origDist = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));

let dist = (travelTimes[stationId] || maxTravelTime) / maxTravelTime;
let dist = (travelTimes[stationId]) / maxTravelTime;
positions[stationId] = {x: Math.cos(angle) * dist, y: Math.sin(angle) * dist};
}

return positions;
}

let stationPositions = computeStationPositions('127'); // times sq
console.log(stationPositions);
let homeStationId = 'R32';
let stationPositions = computeStationPositions(homeStationId); // times sq
// console.log(stationPositions);

let xValue = (stationId) => stationPositions[stationId].x;
let yValue = (stationId) => stationPositions[stationId].y;
Expand All @@ -66,6 +67,7 @@
// let stationList = Object.values(lines)[0].stations;
// svg.selectAll('.stop').data(stationList).enter().append('circle').attr('class', 'stop').attr('r', 3.5).attr('cx', xMap).attr('cy', yMap).style('fill', 'black');
svg.selectAll('.stop').data(Object.keys(stations)).enter().append('circle').attr('class', 'stop').attr('r', '1.5').attr('fill', 'black').attr('cx', xMap).attr('cy', yMap);
svg.selectAll('home').data([homeStationId]).enter().append('circle').attr('class', 'home').attr('r', '3').attr('fill', 'white').attr('stroke', 'black').attr('stroke-width', 2).attr('cx', xMap).attr('cy', yMap);

</script>
</body>
Expand Down
2 changes: 1 addition & 1 deletion subway.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion subway.json

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions virtual_rider.js
@@ -0,0 +1,69 @@

let atStopState = (id) => "at_stop:" + id;
let onTripState = (id) => "on_trip:" + id;

class StateMap {
constructor() {
this.earliestRidersAtStates = {};
}
addRider(rider) {
let existing = this.earliestRidersAtStates[rider.state];
if (!existing || rider.time < existing.time) {
this.earliestRidersAtStates[rider.state] = rider;
return true;
}
return false;
}
addRiderAndTransfersByAppendingStop(oldRider, stopId, time, allTransfers) {
let direct = oldRider.byAdding(atStopState(stopId), time);
if (this.addRider(direct)) {
// add all transfers:
for (let transfer of allTransfers[stopId] || []) {
this.addRiderAndTransfersByAppendingStop(direct, transfer['to'], time + transfer.time, allTransfers);
}
}
}
}

class Rider {
constructor(states, time) {
this.states = states; // parts are strings
this.time = time;
this.state = states.length ? states[states.length-1] : null;
}
byAdding(state, finalTime) {
return new Rider([...this.states, state], finalTime);
}
}

let computeTravelTimes = (startStationId, endStationIds, gtfs_json, startTime, serviceGroup) => {
let stateMap = new StateMap();

let emptyPath = new Rider([], startTime);
stateMap.addRiderAndTransfersByAppendingStop(emptyPath, startStationId, startTime, gtfs_json.transfers);
// console.log(stateMap);

for (let {time, trip_id, stop_id, route_name} of gtfs_json.events_by_service_group[serviceGroup]) {
// model exiting the train:
let riderOnTrain = stateMap.earliestRidersAtStates[onTripState(trip_id)];
if (riderOnTrain && riderOnTrain.time <= time) {
stateMap.addRiderAndTransfersByAppendingStop(riderOnTrain, stop_id, time, gtfs_json.transfers);
}
// model boarding the train:
let riderOnPlatform = stateMap.earliestRidersAtStates[atStopState(stop_id)];
if (riderOnPlatform && riderOnPlatform.time <= time) {
let riderOnTrain = riderOnPlatform.byAdding(onTripState(trip_id), time);
stateMap.addRider(riderOnTrain);
}
}

let travelTimes = {};
for (let stationId of endStationIds) {
let rider = stateMap.earliestRidersAtStates[atStopState(stationId)];
travelTimes[stationId] = rider ? rider.time - startTime : null;
}
return travelTimes;
}

// let HOURS = 60 * 60;
// console.log(computeTravelTimes('127', Object.keys(subway.stations), 8*HOURS, gtfs_json, 'weekdays'));

0 comments on commit f75e14a

Please sign in to comment.