service.py

changeset 92
16a5c37e4e67
parent 91
209f5930d038
child 93
53ee9e945673
equal deleted inserted replaced
91:209f5930d038 92:16a5c37e4e67
266 def is_weekend_night(time): 266 def is_weekend_night(time):
267 from datetime import timedelta 267 from datetime import timedelta
268 adjusted_time = time - timedelta(hours = 4, minutes = 30) 268 adjusted_time = time - timedelta(hours = 4, minutes = 30)
269 return adjusted_time.weekday() in [4, 5] and is_night_time(time) 269 return adjusted_time.weekday() in [4, 5] and is_night_time(time)
270 270
271 encircled = '\u24b6\u24b7\u24b8\u24b9\u24ba\u24bb\u24bc\u24bd\u24be\u24bf' \ 271 #encircled = '\u24b6\u24b7\u24b8\u24b9\u24ba\u24bb\u24bc\u24bd\u24be\u24bf' \
272 '\u24c0\u24c1\u24c2\u24c3\u24c4\u24c5\u24c6\u24c7\u24c8\u24c9\u24ca\u24cb' \ 272 # '\u24c0\u24c1\u24c2\u24c3\u24c4\u24c5\u24c6\u24c7\u24c8\u24c9\u24ca\u24cb' \
273 '\u24cc\u24cd\u24ce\u24cf' 273 # '\u24cc\u24cd\u24ce\u24cf'
274 #encircled = '⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵'
275 encircled = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ'
274 276
275 def encircle(char): 277 def encircle(char):
276 from string import ascii_uppercase 278 from string import ascii_uppercase
277 try: 279 try:
278 return encircled[ascii_uppercase.index(char.upper())] 280 return encircled[ascii_uppercase.index(char.upper())]
293 def describe(bus_stop, week_schedule): 295 def describe(bus_stop, week_schedule):
294 schedule = [] 296 schedule = []
295 from collections import defaultdict, Counter 297 from collections import defaultdict, Counter
296 from busroute import simplify_name 298 from busroute import simplify_name
297 destinations_per_route = defaultdict(Counter) 299 destinations_per_route = defaultdict(Counter)
300 counts_per_variant = {}
298 def route_key(route_ref): 301 def route_key(route_ref):
302 from math import log
299 try: 303 try:
300 return parse_route_ref(route_ref) 304 return () + parse_route_ref(route_ref)
301 except ValueError: 305 except ValueError:
302 return () 306 return ()
303 def filter_names(names): 307 def filter_names(names):
304 if len(names) == 1 and names[0] == (bus_stop.region and simplify_name(bus_stop.region)): 308 if len(names) == 1 and names[0] == (bus_stop.region and simplify_name(bus_stop.region)):
305 return type(names)() 309 return type(names)()
338 all_variants.append({ 342 all_variants.append({
339 'name': route_name, 343 'name': route_name,
340 'destination': filter_names(destination), 344 'destination': filter_names(destination),
341 'count': count 345 'count': count
342 }) 346 })
347 counts_per_variant[route_name] = count
343 all_variants.sort(key = lambda k: k['count']) 348 all_variants.sort(key = lambda k: k['count'])
344 route_variant_count = len(all_variants) 349 route_variant_count = len(all_variants)
345 # Only consider variants so that they cover at least 99% of bus leaves 350 # Only consider variants so that they cover at least 99% of bus leaves
346 coverage = 0 351 coverage = 0
347 while all_variants: #coverage / num_leaves < 0.99: 352 #while coverage / num_leaves < 0.99:
348 variant = all_variants.pop() 353 # variant = all_variants.pop()
354 for variant in all_variants:
349 routes_per_destination[variant['destination']].add(variant['name']) 355 routes_per_destination[variant['destination']].add(variant['name'])
350 coverage += variant['count'] 356 coverage += variant['count']
351 for key in routes_per_destination: 357 for key in routes_per_destination:
352 routes_per_destination[key] = sorted(routes_per_destination[key], key = route_key) 358 routes_per_destination[key] = sorted(routes_per_destination[key], key = route_key)
353 def route_len(route): 359 def route_len(route):
358 else: 364 else:
359 break 365 break
360 return length or len(route) 366 return length or len(route)
361 from math import inf 367 from math import inf
362 def route_key(route): 368 def route_key(route):
369 from math import log
363 return ( 370 return (
364 route in night_routes, 371 route in night_routes,
372 counts_per_variant.get(route, 0) < 20,
365 route_len(route), 373 route_len(route),
366 str(route) 374 str(route)
367 ) 375 )
368 def routes_key(routes): 376 def routes_key(routes):
369 return min(route_key(route) for route in routes) 377 return min(route_key(route) for route in routes)
370 result = [] 378 result = []
379 rare_variants = {variant['name'] for variant in all_variants if variant['count'] < 20}
380 rare_variant_groups = set()
371 for regions, routes in sorted( 381 for regions, routes in sorted(
372 routes_per_destination.items(), 382 routes_per_destination.items(),
373 key = lambda pair: routes_key(pair[1]) 383 key = lambda pair: routes_key(pair[1])
374 ): 384 ):
385 routes_tuple = tuple(condense_route_list(sorted(routes, key = route_key)))
375 result.append(( 386 result.append((
376 list(condense_route_list(sorted(routes, key = route_key))), 387 routes_tuple,
377 ' - '.join(tr(region, 'region_short_name') for region in regions) 388 ' - '.join(tr(region, 'region_short_name') for region in regions)
378 )) 389 ))
390 if all(variant in rare_variants for variant in routes):
391 rare_variant_groups.add(routes_tuple)
379 return { 392 return {
380 'night-routes': night_routes, 393 'night-routes': night_routes,
381 'all-night-routes': lambda entry, description: all(route in description['night-routes'] for route in entry[0]), 394 'all-night-routes': lambda entry, description: all(route in description['night-routes'] for route in entry[0]),
382 'simple': route_variant_count <= 1, 395 'simple': route_variant_count <= 1,
383 'description': result, 396 'description': result,
384 'wtf': destinations_per_route, 397 'wtf': destinations_per_route,
385 'variant-map': {k:variant_names[v] for k, v in trip_mapping.items()}, 398 'variant-map': {k:variant_names[v] for k, v in trip_mapping.items()},
399 'rare-variants': rare_variants,
400 'rare-variant-groups': rare_variant_groups,
386 } 401 }
387 402
388 @app.route('/stop_description/<reference>') 403 @app.route('/stop_description/<reference>')
389 def bus_stop_description(reference): 404 def bus_stop_description(reference):
390 from buses import bus_stops 405 from buses import bus_stops

mercurial