buses.py

changeset 29
2c78e68d7363
parent 28
670ffa424ded
child 30
a5bfd99bc2a3
equal deleted inserted replaced
28:670ffa424ded 29:2c78e68d7363
57 self.dates = set() 57 self.dates = set()
58 def __repr__(self): 58 def __repr__(self):
59 return 'services[%r]' % self.reference 59 return 'services[%r]' % self.reference
60 60
61 class BusStop: 61 class BusStop:
62 def __init__(self, reference, name, location): 62 def __init__(self, reference, name, location, code = None):
63 self.reference, self.name, self.location = reference, name, location 63 self.reference, self.name, self.location = reference, name, location
64 self.code = code or reference
64 self.cluster = None 65 self.cluster = None
65 self.pairs = set() # samannimiset lähellä olevat pysäkit 66 self.pairs = set() # samannimiset lähellä olevat pysäkit
66 self.involved_trips = set() 67 self.involved_trips = set()
67 def __repr__(self): 68 def __repr__(self):
68 return 'bus_stops[%r]' % self.reference 69 return 'bus_stops[%r]' % self.reference
106 # jos tämä ajovuoro ajetaan tänä päivänä 107 # jos tämä ajovuoro ajetaan tänä päivänä
107 if trip.is_served_at(date): 108 if trip.is_served_at(date):
108 # ja jos tämä trip pysähtyy tällä pysäkillä, ei kuitenkaan saapuen 109 # ja jos tämä trip pysähtyy tällä pysäkillä, ei kuitenkaan saapuen
109 # päätepysäkille, 110 # päätepysäkille,
110 stop = trip.contains_stop(self) 111 stop = trip.contains_stop(self)
111 if stop and not stop.isArrival: # stop is not trip.schedule[-1]: 112 if stop and not stop.is_arrival: # stop is not trip.schedule[-1]:
112 # ja jos tämä halt on tulevaisuudessa, 113 # ja jos tämä halt on tulevaisuudessa,
113 stop_time = datetime.combine(date, time()) + stop.arrival_time 114 stop_time = datetime.combine(date, time()) + stop.arrival_time
114 if stop_time >= now(): 115 if stop_time >= now():
115 # lisää halt listaan. 116 # lisää halt listaan.
116 result.append({ 117 result.append({
126 def __init__(self, arrival_time, departure_time, stop, trip, traveled_distance): 127 def __init__(self, arrival_time, departure_time, stop, trip, traveled_distance):
127 self.arrival_time, self.departure_time, self.stop, self.trip = arrival_time, departure_time, \ 128 self.arrival_time, self.departure_time, self.stop, self.trip = arrival_time, departure_time, \
128 stop, trip 129 stop, trip
129 self.traveled_distance = traveled_distance 130 self.traveled_distance = traveled_distance
130 @property 131 @property
131 def isArrival(self): 132 def is_arrival(self):
132 if not hasattr(self, 'cachedIsArrival'): 133 if not hasattr(self, 'cachedIsArrival'):
133 iterator = iter(self.trip.schedule) 134 if self.stop.region:
134 stop = next(iterator) 135 iterator = iter(self.trip.schedule)
135 while stop is not self:
136 stop = next(iterator) 136 stop = next(iterator)
137 for stop in iterator: 137 while stop is not self:
138 if stop.stop.region != self.stop.region: 138 stop = next(iterator)
139 self.cachedIsArrival = False 139 for stop in iterator:
140 break 140 if stop.stop.region != self.stop.region:
141 self.cachedIsArrival = False
142 break
143 else:
144 self.cachedIsArrival = True
141 else: 145 else:
142 self.cachedIsArrival = True 146 self.cachedIsArrival = False
143 return self.cachedIsArrival 147 return self.cachedIsArrival
144 def __repr__(self): 148 def __repr__(self):
145 return 'BusHalt(%r, %r, %r, %r)' % (self.arrival_time, self.departure_time, self.stop, self.trip) 149 return 'BusHalt(%r, %r, %r, %r)' % (self.arrival_time, self.departure_time, self.stop, self.trip)
146 150
147 routes = {} 151 routes = {}
180 route.trips.add(trip) 184 route.trips.add(trip)
181 assert trip.name not in all_trips 185 assert trip.name not in all_trips
182 all_trips[trip.name] = trip 186 all_trips[trip.name] = trip
183 print('%d ajoa' % len(all_trips), file = stderr) 187 print('%d ajoa' % len(all_trips), file = stderr)
184 188
185 def lue_päiväys(teksti): 189 def read_date(teksti):
186 return date(int(teksti[:4]), int(teksti[4:6]), int(teksti[6:])) 190 return date(int(teksti[:4]), int(teksti[4:6]), int(teksti[6:]))
187 191
188 def read_time(teksti): 192 def read_time(teksti):
189 tunti, minuutti, sekunti = map(int, teksti.split(':')) 193 tunti, minuutti, sekunti = map(int, teksti.split(':'))
190 return timedelta(hours = tunti, minutes = minuutti, seconds = sekunti) 194 return timedelta(hours = tunti, minutes = minuutti, seconds = sekunti)
192 print('Ladataan päiväykset... ', file = stderr, flush = True) 196 print('Ladataan päiväykset... ', file = stderr, flush = True)
193 197
194 viimeinen_käyttöpäivä = date.today() 198 viimeinen_käyttöpäivä = date.today()
195 services_for_day = {} 199 services_for_day = {}
196 200
197 with open('gtfs/calendar_dates.txt') as file: 201 def date_range(start_date, end_date, *, include_end = False):
198 for row in read_csv(file): 202 ''' Generates date from start_date to end_date. If include_end is True, then end_date will be yielded. '''
199 service = services[row['service_id']] 203 current_date = start_date
200 day = lue_päiväys(row['date']) 204 while current_date < end_date:
205 yield current_date
206 current_date += timedelta(1)
207 if include_end:
208 yield end_date
209
210 def add_day_to_service(service_name, day):
211 try:
212 service = services[service_name]
213 except KeyError:
214 return
215 else:
201 service.dates.add(day) 216 service.dates.add(day)
202 if day not in services_for_day: 217 if day not in services_for_day:
203 services_for_day[day] = set() 218 services_for_day[day] = set()
204 services_for_day[day].add(service) 219 services_for_day[day].add(service)
220 global viimeinen_käyttöpäivä
205 viimeinen_käyttöpäivä = max(day, viimeinen_käyttöpäivä) 221 viimeinen_käyttöpäivä = max(day, viimeinen_käyttöpäivä)
222
223 def filter_day(row, day):
224 day_names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
225 return int(row[day_names[day.isoweekday() - 1]])
226
227 with open('gtfs/calendar.txt') as file:
228 for row in read_csv(file):
229 for day in date_range(read_date(row['start_date']), read_date(row['end_date']), include_end = True):
230 if filter_day(row, day):
231 add_day_to_service(service_name = row['service_id'], day = day)
232
233 with open('gtfs/calendar_dates.txt') as file:
234 for row in read_csv(file):
235 add_day_to_service(service_name = row['service_id'], day = read_date(row['date']))
206 236
207 def services_available_at(day): 237 def services_available_at(day):
208 for service in services.values(): 238 for service in services.values():
209 if day in service.dates: 239 if day in service.dates:
210 yield service 240 yield service
211 241
212 print('Ladataan pysäkit... ', file = stderr, end = '', flush = True) 242 print('Ladataan pysäkit... ', file = stderr, end = '', flush = True)
213 with open('gtfs/stops.txt') as file: 243 with open('gtfs/stops.txt') as file:
214 for row in read_csv(file): 244 for row in read_csv(file):
215 location = Sijainti(float(row['stop_lat']), float(row['stop_lon'])) 245 location = Sijainti(float(row['stop_lat']), float(row['stop_lon']))
216 stop = BusStop(row['stop_id'], row['stop_name'], location) 246 stop = BusStop(
247 reference = row['stop_id'],
248 name = row['stop_name'],
249 location = location,
250 code = row['stop_code'],
251 )
217 bus_stops[stop.reference] = stop 252 bus_stops[stop.reference] = stop
218 with open('regions-per-stop.json') as file: 253 with open('regions-per-stop.json') as file:
219 for stop_reference, region in json.load(file).items(): 254 for stop_reference, region in json.load(file).items():
220 bus_stops[stop_reference].region = region 255 bus_stops[stop_reference].region = region
221 print('%d pysäkkiä' % len(bus_stops), file = stderr) 256 print('%d pysäkkiä' % len(bus_stops), file = stderr)
274 if not bus_stop.cluster: 309 if not bus_stop.cluster:
275 stops_to_cluster = {bus_stop} 310 stops_to_cluster = {bus_stop}
276 # etsi pysäkin samannimiset vastaparit 311 # etsi pysäkin samannimiset vastaparit
277 for pair_candidate in bus_stops_by_name[bus_stop.name]: 312 for pair_candidate in bus_stops_by_name[bus_stop.name]:
278 distance = pair_candidate.location.etäisyys(bus_stop.location) 313 distance = pair_candidate.location.etäisyys(bus_stop.location)
279 if pair_candidate is not bus_stop and distance <= 0.3: 314 if pair_candidate is not bus_stop and distance <= 0.4:
280 stops_to_cluster.add(pair_candidate) 315 stops_to_cluster.add(pair_candidate)
281 for stop_to_cluster in stops_to_cluster: 316 for stop_to_cluster in stops_to_cluster:
282 if stop_to_cluster.cluster: 317 if stop_to_cluster.cluster:
283 cluster = stop_to_cluster.cluster 318 cluster = stop_to_cluster.cluster
284 break 319 break
297 if len(bus_stop.cluster.stops) == 1: 332 if len(bus_stop.cluster.stops) == 1:
298 possibilities = set() 333 possibilities = set()
299 for cluster in all_clusters: 334 for cluster in all_clusters:
300 if cluster is not bus_stop.cluster: 335 if cluster is not bus_stop.cluster:
301 distance = cluster.center.etäisyys(bus_stop.location) 336 distance = cluster.center.etäisyys(bus_stop.location)
302 if distance <= 0.3: 337 if distance <= 0.4:
303 possibilities.add((distance, cluster)) 338 possibilities.add((distance, cluster))
304 if possibilities: 339 if possibilities:
305 best = min(possibilities)[1] 340 best = min(possibilities)[1]
306 all_clusters.remove(bus_stop.cluster) 341 all_clusters.remove(bus_stop.cluster)
307 best.merge(bus_stop.cluster) 342 best.merge(bus_stop.cluster)
354 cluster_bus_stops() 389 cluster_bus_stops()
355 name_clusters() 390 name_clusters()
356 391
357 clusters_by_name = {} 392 clusters_by_name = {}
358 for cluster in all_clusters: 393 for cluster in all_clusters:
359 assert cluster.url_name not in clusters_by_name 394 if cluster.url_name in clusters_by_name:
360 clusters_by_name[cluster.url_name] = cluster 395 print('Warning: Clusters %r and %r share the same URL name: %r' % (cluster.name, clusters_by_name[cluster.url_name].name, cluster.url_name))
396 else:
397 clusters_by_name[cluster.url_name] = cluster
361 398
362 print('Ladataan aikataulut... ', end = '', flush = True, file = stderr) 399 print('Ladataan aikataulut... ', end = '', flush = True, file = stderr)
363 with open('gtfs/stop_times.txt') as file: 400 with open('gtfs/stop_times.txt') as file:
364 row_count = sum(line.count('\n') for line in file) 401 row_count = sum(line.count('\n') for line in file)
365 progress = 0 402 progress = 0

mercurial