Sat, 24 Jun 2017 19:38:05 +0300
Lisää päivityksiä
.hgignore | file | annotate | diff | comparison | revisions | |
buses.py | file | annotate | diff | comparison | revisions | |
profiles/föli.cfg | file | annotate | diff | comparison | revisions | |
profiles/föli.ini | file | annotate | diff | comparison | revisions | |
profiles/hsl.cfg | file | annotate | diff | comparison | revisions | |
profiles/hsl.ini | file | annotate | diff | comparison | revisions | |
region-representatives.json | file | annotate | diff | comparison | revisions | |
regions.gmp | file | annotate | diff | comparison | revisions | |
service.py | file | annotate | diff | comparison | revisions | |
static/style.css | file | annotate | diff | comparison | revisions | |
templates/cluster.html | file | annotate | diff | comparison | revisions | |
tr/en.ini | file | annotate | diff | comparison | revisions | |
tr/fi.ini | file | annotate | diff | comparison | revisions | |
tr/sv.ini | file | annotate | diff | comparison | revisions |
--- a/.hgignore Thu Jun 22 19:01:31 2017 +0300 +++ b/.hgignore Sat Jun 24 19:38:05 2017 +0300 @@ -1,5 +1,5 @@ syntax:glob __pycache__ gtfs -gtfs.zip +gtfs*.zip regions-per-stop.json
--- a/buses.py Thu Jun 22 19:01:31 2017 +0300 +++ b/buses.py Sat Jun 24 19:38:05 2017 +0300 @@ -154,294 +154,314 @@ services = {} bus_stops = {} all_clusters = set() - -print('Ladataan routes... ', file = stderr, end = '', flush = True) -with open('gtfs/routes.txt') as file: - for row in read_csv(file): - route = BusRoute(row) - routes[route.reference] = route - routes_per_id[route.id] = route -print('%d linjaa' % len(routes), file = stderr) - -print('Ladataan ajovuorot... ', file = stderr, end = '', flush = True) - -shape_distances = {} -with open('gtfs/shapes.txt') as file: - for row in read_csv(file): - shape_distances[row['shape_id']] = max(shape_distances.get(row['shape_id'], 0), float(row['shape_dist_traveled'])) - -with open('gtfs/trips.txt') as file: - for row in read_csv(file): - if row['service_id'] not in services: - services[row['service_id']] = BusService(row['service_id']) - route = routes_per_id[row['route_id']] - trip = BusTrip( - reference = row['trip_id'], - route = route, - service = services[row['service_id']], - length = shape_distances[row['shape_id']] - ) - route.trips.add(trip) - assert trip.name not in all_trips - all_trips[trip.name] = trip -print('%d ajoa' % len(all_trips), file = stderr) - -def read_date(teksti): - return date(int(teksti[:4]), int(teksti[4:6]), int(teksti[6:])) - -def read_time(teksti): - tunti, minuutti, sekunti = map(int, teksti.split(':')) - return timedelta(hours = tunti, minutes = minuutti, seconds = sekunti) - -print('Ladataan päiväykset... ', file = stderr, flush = True) - -viimeinen_käyttöpäivä = date.today() +viimeinen_käyttöpäivä = None +clusters_by_name = {} services_for_day = {} -def date_range(start_date, end_date, *, include_end = False): - ''' Generates date from start_date to end_date. If include_end is True, then end_date will be yielded. ''' - current_date = start_date - while current_date < end_date: - yield current_date - current_date += timedelta(1) - if include_end: - yield end_date +def load_buses(gtfs_zip_path, profile): + global viimeinen_käyttöpäivä + from zipfile import ZipFile + with ZipFile(gtfs_zip_path) as gtfs_zip: + print('Ladataan linjat... ', file = stderr, end = '', flush = True) + with gtfs_zip.open('routes.txt') as file: + for row in read_csv(map(bytes.decode, file)): + route = BusRoute(row) + routes[route.reference] = route + routes_per_id[route.id] = route + print('%d linjaa' % len(routes), file = stderr) + + print('Ladataan ajovuorot... ', file = stderr, end = '', flush = True) + + shape_distances = {} + with gtfs_zip.open('shapes.txt') as file: + for row in read_csv(map(bytes.decode, file)): + shape_distances[row['shape_id']] = max(shape_distances.get(row['shape_id'], 0), float(row['shape_dist_traveled'])) -def add_day_to_service(service_name, day): - try: - service = services[service_name] - except KeyError: - return - else: - service.dates.add(day) - if day not in services_for_day: - services_for_day[day] = set() - services_for_day[day].add(service) - global viimeinen_käyttöpäivä - viimeinen_käyttöpäivä = max(day, viimeinen_käyttöpäivä) + with gtfs_zip.open('trips.txt') as file: + for row in read_csv(map(bytes.decode, file)): + if row['service_id'] not in services: + services[row['service_id']] = BusService(row['service_id']) + route = routes_per_id[row['route_id']] + trip = BusTrip( + reference = row['trip_id'], + route = route, + service = services[row['service_id']], + length = shape_distances[row['shape_id']] * float(profile['metrics']['shape-modifier']) + ) + route.trips.add(trip) + assert trip.name not in all_trips + all_trips[trip.name] = trip + print('%d ajoa' % len(all_trips), file = stderr) -def filter_day(row, day): - day_names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] - return int(row[day_names[day.isoweekday() - 1]]) + def read_date(teksti): + return date(int(teksti[:4]), int(teksti[4:6]), int(teksti[6:])) + + def read_time(teksti): + tunti, minuutti, sekunti = map(int, teksti.split(':')) + return timedelta(hours = tunti, minutes = minuutti, seconds = sekunti) + + print('Ladataan päiväykset... ', file = stderr, flush = True) + + viimeinen_käyttöpäivä = date.today() -with open('gtfs/calendar.txt') as file: - for row in read_csv(file): - for day in date_range(read_date(row['start_date']), read_date(row['end_date']), include_end = True): - if filter_day(row, day): - add_day_to_service(service_name = row['service_id'], day = day) + def date_range(start_date, end_date, *, include_end = False): + ''' Generates date from start_date to end_date. If include_end is True, then end_date will be yielded. ''' + current_date = start_date + while current_date < end_date: + yield current_date + current_date += timedelta(1) + if include_end: + yield end_date -with open('gtfs/calendar_dates.txt') as file: - for row in read_csv(file): - add_day_to_service(service_name = row['service_id'], day = read_date(row['date'])) + def add_day_to_service(service_name, day): + try: + service = services[service_name] + except KeyError: + return + else: + service.dates.add(day) + if day not in services_for_day: + services_for_day[day] = set() + services_for_day[day].add(service) + global viimeinen_käyttöpäivä + viimeinen_käyttöpäivä = max(day, viimeinen_käyttöpäivä) -def services_available_at(day): - for service in services.values(): - if day in service.dates: - yield service + def filter_day(row, day): + day_names = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] + return int(row[day_names[day.isoweekday() - 1]]) -print('Ladataan pysäkit... ', file = stderr, end = '', flush = True) -with open('gtfs/stops.txt') as file: - for row in read_csv(file): - location = Sijainti(float(row['stop_lat']), float(row['stop_lon'])) - stop = BusStop( - reference = row['stop_id'], - name = row['stop_name'], - location = location, - code = row['stop_code'], - ) - bus_stops[stop.reference] = stop -with open('regions-per-stop.json') as file: - for stop_reference, region in json.load(file).items(): - bus_stops[stop_reference].region = region -print('%d pysäkkiä' % len(bus_stops), file = stderr) + with gtfs_zip.open('calendar.txt') as file: + for row in read_csv(map(bytes.decode, file)): + for day in date_range(read_date(row['start_date']), read_date(row['end_date']), include_end = True): + if filter_day(row, day): + add_day_to_service(service_name = row['service_id'], day = day) + + with gtfs_zip.open('calendar_dates.txt') as file: + for row in read_csv(map(bytes.decode, file)): + add_day_to_service(service_name = row['service_id'], day = read_date(row['date'])) + + def services_available_at(day): + for service in services.values(): + if day in service.dates: + yield service + + print('Ladataan pysäkit... ', file = stderr, end = '', flush = True) + with gtfs_zip.open('stops.txt') as file: + for row in read_csv(map(bytes.decode, file)): + location = Sijainti(float(row['stop_lat']), float(row['stop_lon'])) + stop = BusStop( + reference = row['stop_id'], + name = row['stop_name'], + location = location, + code = row['stop_code'], + ) + bus_stops[stop.reference] = stop + with open('regions-per-stop.json') as file: + for stop_reference, region in json.load(file).items(): + bus_stops[stop_reference].region = region + print('%d pysäkkiä' % len(bus_stops), file = stderr) -class BusStopCluster: - def __init__(self): - self.stops = set() - self._center = None - self.name = None - @property - def url_name(self): - return self.name.lower().replace('(', '').replace(')', '').replace(' ', '-') - def add_stop(self, stop): - assert not stop.cluster - stop.cluster = self - self.stops.add(stop) - self._center = None - @property - def center(self): - if not self._center: - if self.stops: - from statistics import median - pointtype = type(next(iter(self.stops)).location) - self._center = pointtype( - median(stop.location.x for stop in self.stops), - median(stop.location.y for stop in self.stops), - ) - else: - raise ValueError('an empty cluster has no center point') - return self._center - def merge(self, other): - for bus_stop in other.stops: - bus_stop.cluster = self - self.stops |= other.stops - other.stops = set() - other._center = None - def schedule(self, max_amount = 50): - result = [] - for stop in self.stops: - result += stop.schedule(max_amount) - result.sort(key = lambda schedule_entry: schedule_entry['time']) - return result[:max_amount] + class BusStopCluster: + def __init__(self): + self.stops = set() + self._center = None + self.name = None + @property + def url_name(self): + return self.name.lower().replace('(', '').replace(')', '').replace(' ', '-') + def add_stop(self, stop): + assert not stop.cluster + stop.cluster = self + self.stops.add(stop) + self._center = None + @property + def center(self): + if not self._center: + if self.stops: + from statistics import median + pointtype = type(next(iter(self.stops)).location) + self._center = pointtype( + median(stop.location.x for stop in self.stops), + median(stop.location.y for stop in self.stops), + ) + else: + raise ValueError('an empty cluster has no center point') + return self._center + def merge(self, other): + for bus_stop in other.stops: + bus_stop.cluster = self + self.stops |= other.stops + other.stops = set() + other._center = None + def schedule(self, max_amount = 50): + result = [] + for stop in self.stops: + result += stop.schedule(max_amount) + result.sort(key = lambda schedule_entry: schedule_entry['time']) + return result[:max_amount] -from collections import defaultdict -bus_stops_by_name = defaultdict(set) -for bus_stop in bus_stops.values(): - bus_stops_by_name[bus_stop.name].add(bus_stop) -bus_stops_by_name = dict(bus_stops_by_name) + from collections import defaultdict + bus_stops_by_name = defaultdict(set) + for bus_stop in bus_stops.values(): + bus_stops_by_name[bus_stop.name].add(bus_stop) + bus_stops_by_name = dict(bus_stops_by_name) -# ryhmittele bus_stops nimen mukaan -all_clusters = [] -def cluster_bus_stops(): - sorted_bus_stops = sorted(bus_stops.values(), key = lambda bus_stop: bus_stop.name) - for bus_stop in sorted_bus_stops: - if not bus_stop.cluster: - stops_to_cluster = {bus_stop} - # etsi pysäkin samannimiset vastaparit - for pair_candidate in bus_stops_by_name[bus_stop.name]: - distance = pair_candidate.location.etäisyys(bus_stop.location) - if pair_candidate is not bus_stop and distance <= 0.4: - stops_to_cluster.add(pair_candidate) - for stop_to_cluster in stops_to_cluster: - if stop_to_cluster.cluster: - cluster = stop_to_cluster.cluster - break - else: - cluster = BusStopCluster() - all_clusters.append(cluster) - for stop_to_cluster in stops_to_cluster: - if not stop_to_cluster.cluster: - cluster.add_stop(stop_to_cluster) - # Merkitse muistiin pysäkkien vastaparit käyttäen hyväksi tämänhetkistä ryhmittelytietoa - for bus_stop in bus_stops.values(): - if bus_stop.cluster: - bus_stop.pairs = bus_stop.cluster.stops - {bus_stop} - # Ryhmitä ne bus_stops, joilla ei ollut omaa vastaparia, muiden pysäkkien kanssa - for bus_stop in sorted_bus_stops: - if len(bus_stop.cluster.stops) == 1: - possibilities = set() - for cluster in all_clusters: - if cluster is not bus_stop.cluster: - distance = cluster.center.etäisyys(bus_stop.location) - if distance <= 0.4: - possibilities.add((distance, cluster)) - if possibilities: - best = min(possibilities)[1] - all_clusters.remove(bus_stop.cluster) - best.merge(bus_stop.cluster) + # ryhmittele bus_stops nimen mukaan + all_clusters = [] + def cluster_bus_stops(): + sorted_bus_stops = sorted(bus_stops.values(), key = lambda bus_stop: bus_stop.name) + for bus_stop in sorted_bus_stops: + if not bus_stop.cluster: + stops_to_cluster = {bus_stop} + # etsi pysäkin samannimiset vastaparit + for pair_candidate in bus_stops_by_name[bus_stop.name]: + distance = pair_candidate.location.etäisyys(bus_stop.location) + if pair_candidate is not bus_stop and distance <= 0.4: + stops_to_cluster.add(pair_candidate) + for stop_to_cluster in stops_to_cluster: + if stop_to_cluster.cluster: + cluster = stop_to_cluster.cluster + break + else: + cluster = BusStopCluster() + all_clusters.append(cluster) + for stop_to_cluster in stops_to_cluster: + if not stop_to_cluster.cluster: + cluster.add_stop(stop_to_cluster) + # Merkitse muistiin pysäkkien vastaparit käyttäen hyväksi tämänhetkistä ryhmittelytietoa + for bus_stop in bus_stops.values(): + if bus_stop.cluster: + bus_stop.pairs = bus_stop.cluster.stops - {bus_stop} + # Ryhmitä ne bus_stops, joilla ei ollut omaa vastaparia, muiden pysäkkien kanssa + for bus_stop in sorted_bus_stops: + if len(bus_stop.cluster.stops) == 1: + possibilities = set() + for cluster in all_clusters: + if cluster is not bus_stop.cluster: + distance = cluster.center.etäisyys(bus_stop.location) + if distance <= 0.4: + possibilities.add((distance, cluster)) + if possibilities: + best = min(possibilities)[1] + all_clusters.remove(bus_stop.cluster) + best.merge(bus_stop.cluster) -def shared_elements_in_n_sets(sets): - from itertools import combinations - result = set() - for pair in combinations(sets, 2): - result |= pair[0] & pair[1] - return result + def shared_elements_in_n_sets(sets): + from itertools import combinations + result = set() + for pair in combinations(sets, 2): + result |= pair[0] & pair[1] + return result -def name_clusters(): - from collections import defaultdict - from pprint import pprint - clusters_per_name = defaultdict(set) - for cluster in all_clusters: - name_representing_stop = min((len(stop.reference), stop.reference, stop) for stop in cluster.stops)[2] - clusters_per_name[name_representing_stop.name].add(cluster) - for name, clusters in clusters_per_name.items(): - if len(clusters) == 1: - # Ryhmä on ainoa jolla on varaus tälle nimelle. Sen kuin vaan. - next(iter(clusters)).name = name - else: - # Olisiko kaikki klusterit eri alueilla? - common_regions = shared_elements_in_n_sets({stop.region for stop in cluster.stops} for cluster in clusters) - # Esitys: ryhmä -> ne alueet jotka ovat tälle ryhmälle ainutlaatuisia - proposal = { - cluster: {stop.region for stop in cluster.stops} - common_regions - {None} - for cluster in clusters - } - # Jos enintään yksi klusteri tässä esityksessä on kokonaan ilman omaa aluetta, jolla se voisi eritellä, - # niin nimetään klusterit näiden alueiden mukaan. - # Se klusteri jolla ei ole omaa aluetta (jos on) jätetään ilman aluepäätettä. - if sum([1 for unique_areas in proposal.values() if not unique_areas]) <= 1: - for cluster, unique_areas in proposal.items(): - individual_cluster_name = name - if unique_areas: - individual_cluster_name += ' (' + min(unique_areas) + ')' - cluster.name = individual_cluster_name + def name_clusters(): + from collections import defaultdict + from pprint import pprint + clusters_per_name = defaultdict(set) + for cluster in all_clusters: + name_representing_stop = min((len(stop.reference), stop.reference, stop) for stop in cluster.stops)[2] + clusters_per_name[name_representing_stop.name].add(cluster) + for name, clusters in clusters_per_name.items(): + if len(clusters) == 1: + # Ryhmä on ainoa jolla on varaus tälle nimelle. Sen kuin vaan. + next(iter(clusters)).name = name + else: + # Olisiko kaikki klusterit eri alueilla? + common_regions = shared_elements_in_n_sets({stop.region for stop in cluster.stops} for cluster in clusters) + # Esitys: ryhmä -> ne alueet jotka ovat tälle ryhmälle ainutlaatuisia + proposal = { + cluster: {stop.region for stop in cluster.stops} - common_regions - {None} + for cluster in clusters + } + # Jos enintään yksi klusteri tässä esityksessä on kokonaan ilman omaa aluetta, jolla se voisi eritellä, + # niin nimetään klusterit näiden alueiden mukaan. + # Se klusteri jolla ei ole omaa aluetta (jos on) jätetään ilman aluepäätettä. + if sum([1 for unique_areas in proposal.values() if not unique_areas]) <= 1: + for cluster, unique_areas in proposal.items(): + individual_cluster_name = name + if unique_areas: + individual_cluster_name += ' (' + min(unique_areas) + ')' + cluster.name = individual_cluster_name + else: + # Typerä reunatapaus. Indeksoidaan numeroin... + for n, (_, cluster) in enumerate(sorted( + min((stop.reference.lower(), cluster) for stop in cluster.stops) + for cluster in clusters + ), 1): + individual_cluster_name = name + '-' + str(n) + cluster.name = individual_cluster_name + + print('Ryhmitellään pysäkit...') + cluster_bus_stops() + name_clusters() + + for cluster in all_clusters: + if cluster.url_name in clusters_by_name: + print('Warning: Clusters %r and %r share the same URL name: %r' % (cluster.name, clusters_by_name[cluster.url_name].name, cluster.url_name)) else: - # Typerä reunatapaus. Indeksoidaan numeroin... - for n, (_, cluster) in enumerate(sorted( - min((stop.reference.lower(), cluster) for stop in cluster.stops) - for cluster in clusters - ), 1): - individual_cluster_name = name + '-' + str(n) - cluster.name = individual_cluster_name - -print('Ryhmitellään pysäkit...') -cluster_bus_stops() -name_clusters() - -clusters_by_name = {} -for cluster in all_clusters: - if cluster.url_name in clusters_by_name: - print('Warning: Clusters %r and %r share the same URL name: %r' % (cluster.name, clusters_by_name[cluster.url_name].name, cluster.url_name)) - else: - clusters_by_name[cluster.url_name] = cluster + clusters_by_name[cluster.url_name] = cluster -print('Ladataan aikataulut... ', end = '', flush = True, file = stderr) -with open('gtfs/stop_times.txt') as file: - row_count = sum(line.count('\n') for line in file) - progress = 0 - file.seek(0) - for row in read_csv(file): - trip = all_trips[transform_trip_reference(row['trip_id'])] - arrival_time = read_time(row['arrival_time']) - departure_time = read_time(row['departure_time']) - stop = bus_stops[row['stop_id']] - traveled_distance = float(row['shape_dist_traveled']) - trip.schedule.append(BusHalt(arrival_time, departure_time, stop, trip, traveled_distance)) - stop.involved_trips.add(trip) - progress += 1 - if progress % 1000 == 0: - print('\rLadataan aikataulut... %.1f%%' % (progress * 100 / row_count), end = ' ', file = stderr) -print('\rLadataan aikataulut... ladattu', file = stderr) + print('Ladataan aikataulut... ', end = '', flush = True, file = stderr) + with gtfs_zip.open('stop_times.txt') as file: + row_count = sum(line.count(b'\n') for line in file) + with gtfs_zip.open('stop_times.txt') as file: + progress = 0 + for row in read_csv(map(bytes.decode, file)): + trip = all_trips[transform_trip_reference(row['trip_id'])] + arrival_time = read_time(row['arrival_time']) + departure_time = read_time(row['departure_time']) + stop = bus_stops[row['stop_id']] + traveled_distance = float(row['shape_dist_traveled']) * float(profile['metrics']['shape-modifier']) + trip.schedule.append(BusHalt(arrival_time, departure_time, stop, trip, traveled_distance)) + stop.involved_trips.add(trip) + progress += 1 + if progress % 1000 == 0: + print('\rLadataan aikataulut... %.1f%%' % (progress * 100 / row_count), end = ' ', file = stderr) + print('\rLadataan aikataulut... ladattu', file = stderr) + + for trip in all_trips.values(): + from busroute import simplify_name + schedule = trip.concise_schedule() + try: + trip.from_place = simplify_name(schedule[0]) + trip.to_place = simplify_name(schedule[-1]) + except IndexError: + trip.from_place = '' + trip.to_place = '' -for trip in all_trips.values(): - from busroute import simplify_name - schedule = trip.concise_schedule() - try: - trip.from_place = simplify_name(schedule[0]) - trip.to_place = simplify_name(schedule[-1]) - except IndexError: - trip.from_place = '' - trip.to_place = '' + for route in routes.values(): + from collections import Counter + from busroute import simplify_name + tally = Counter() + for trip in route.trips: + schedule = trip.concise_schedule() + places = set(schedule) + do_add = True + assert type(schedule) is list + for candidate in tally: + if places.issubset(set(candidate)): + do_add = False + tally.update({tuple(candidate)}) + if do_add: + tally.update({tuple(schedule)}) + try: + most_common_route = tally.most_common(1)[0][0] + route.description = simplify_name(most_common_route[0]) + ' - ' + simplify_name(most_common_route[-1]) + except: + route.description = '' + route.trips = sorted(route.trips, key = lambda trip: trip.schedule[0].departure_time) -for route in routes.values(): - from collections import Counter - from busroute import simplify_name - tally = Counter() - for trip in route.trips: - schedule = trip.concise_schedule() - places = set(schedule) - do_add = True - assert type(schedule) is list - for candidate in tally: - if places.issubset(set(candidate)): - do_add = False - tally.update({tuple(candidate)}) - if do_add: - tally.update({tuple(schedule)}) - try: - most_common_route = tally.most_common(1)[0][0] - route.description = simplify_name(most_common_route[0]) + ' - ' + simplify_name(most_common_route[-1]) - except: - route.description = '' - route.trips = sorted(route.trips, key = lambda trip: trip.schedule[0].departure_time) + # Fölin datassa on jotain tosi kummaa. Ilmeisesti ajovuoron viimeisen pysähdyksen saapumisaika on ihan täysin + # väärin. Arvaan että se on seuraavan lähdön aika, mutta joka tapauksessa se on väärin. + # Arvataan mikä se todellinen saapumisaika on. Se ei voi mennä kauhean paljon pahemmin vikaan kuin alkuperäinen + # väärin oleva data. + for trip in all_trips.values(): + bus_speed_coefficient = 750 # metriä minuutissa + last_leg_distance = trip.schedule[-1].traveled_distance - trip.schedule[-2].traveled_distance + trip.schedule[-1].arrival_time = trip.schedule[-2].departure_time + timedelta(minutes = last_leg_distance / bus_speed_coefficient) + +if __name__ == '__main__': + from configparser import ConfigParser + profile = ConfigParser() + profile.read('profiles/föli.ini') + load_buses('gtfs.zip', profile)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/föli.ini Sat Jun 24 19:38:05 2017 +0300 @@ -0,0 +1,2 @@ +[metrics] +shape-modifier = 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/profiles/hsl.ini Sat Jun 24 19:38:05 2017 +0300 @@ -0,0 +1,6 @@ +[metrics] +shape-modifier = 1000 + +[service-patterns] +light-rail = [A-Z] +metro = M\d+
--- a/region-representatives.json Thu Jun 22 19:01:31 2017 +0300 +++ b/region-representatives.json Sat Jun 24 19:38:05 2017 +0300 @@ -89,6 +89,7 @@ "Kaivola": "3229", "Kakskerta": "1764", "Kastu": "627", + "Kasarmialue": "1797", "Katariina": "516", "Kauppatori": "T1", "Kerttuli": "867", @@ -111,6 +112,7 @@ "Lauste": "708", "Lauttaranta": "128", "Lentoasema": "1586", + "Lehmusvalkama": "1802", "Liljalaakso": "592", "Linja-autoasema": "41", "Linnavuori": "3122", @@ -201,7 +203,7 @@ "Velusmaa": "3287", "Vähä-Heikkilä": "944", "Yli-Maaria": "396", - "Yliopistonmäki": "1797", + "Yliopisto": "65", "Ylioppilaskylä-Länsi": "445", "Ylioppilaskylä-Itä": "448", "Meripirtti": "3179",
--- a/regions.gmp Thu Jun 22 19:01:31 2017 +0300 +++ b/regions.gmp Sat Jun 24 19:38:05 2017 +0300 @@ -1,9 +1,8 @@ -roadmap^60.407187649046506, 22.331562262097012^16@undefined^#FF0000,5,1,#ff8800,0.4^^60.39482,22.2577~60.40037,22.27521~60.39147,22.28456~60.38851,22.27179 -polygon^#FF0000,5,1,#ff8800,0.4^^60.3977,22.24465~60.40772,22.24046~60.40792,22.26057~60.40076,22.27409~60.3952,22.25642 +roadmap^60.435782981983806, 22.304026704350125^15@polygon^#FF0000,5,1,#ff8800,0.4^^60.3977,22.24465~60.40772,22.24046~60.40792,22.26057~60.40076,22.27409~60.3952,22.25642 polygon^#FF0000,5,1,#ff8800,0.4^^60.3977,22.22706~60.38719,22.23676~60.38341,22.22466~60.38518,22.21205~60.39359,22.20706~60.39816,22.21341 -undefined^#FF0000,5,1,#ff8800,0.4^^60.39868,22.21599~60.39804,22.22852~60.38876,22.23916~60.38952,22.24843~60.39329,22.25135~60.40217,22.23474~60.4019,22.21689 -undefined^#FF0000,5,1,#ff8800,0.4^^60.38871,22.16432~60.39236,22.18483~60.39972,22.188~60.40171,22.1823~60.39919,22.15413~60.39151,22.15633 -undefined^#FF0000,5,1,#ff8800,0.4^^60.42123,22.17264~60.41472,22.15422~60.40622,22.14277~60.40003,22.15599~60.40577,22.17143~60.41357,22.18174 +polygon^#FF0000,5,1,#ff8800,0.4^^60.39868,22.21599~60.39804,22.22852~60.38876,22.23916~60.38952,22.24843~60.39329,22.25135~60.40217,22.23474~60.4019,22.21689 +polygon^#FF0000,5,1,#ff8800,0.4^^60.38871,22.16432~60.39236,22.18483~60.39972,22.188~60.40171,22.1823~60.39919,22.15413~60.39151,22.15633 +polygon^#FF0000,5,1,#ff8800,0.4^^60.42123,22.17264~60.41472,22.15422~60.40622,22.14277~60.40003,22.15599~60.40577,22.17143~60.41357,22.18174 undefined^#FF0000,5,1,#ff8800,0.4^^60.43275,22.20869~60.4239,22.21632~60.41889,22.19831~60.42495,22.19216~60.43033,22.19648 undefined^#FF0000,5,1,#ff8800,0.4^^60.42148,22.17333~60.42584,22.18964~60.41902,22.1971~60.41534,22.18056 undefined^#FF0000,5,1,#ff8800,0.4^^60.49702,22.21496~60.49936,22.22028~60.50048,22.23744~60.49676,22.2392~60.49373,22.23435~60.49306,22.23554~60.49178,22.23402~60.48872,22.22903~60.48729,22.2221~60.49085,22.21505 @@ -65,7 +64,6 @@ undefined^#FF0000,5,1,#ff8800,0.4^^60.48122,22.18547~60.47853,22.19719~60.47645,22.20365~60.47299,22.19482 undefined^#FF0000,5,1,#ff8800,0.4^^60.49404,22.26856~60.49248,22.28712~60.48973,22.30216~60.48271,22.29808~60.47627,22.28925~60.47537,22.27866~60.47564,22.26596~60.48309,22.27138~60.48695,22.27301 undefined^#FF0000,5,1,#ff8800,0.4^^60.43241,22.32263~60.4233,22.33585~60.42025,22.32107~60.42818,22.31196~60.43215,22.31439~60.43258,22.31667 -undefined^#FF0000,5,1,#ff8800,0.4^^60.4422,22.29864~60.43473,22.30327~60.43438,22.32316~60.43887,22.3172~60.44454,22.30841 undefined^#FF0000,5,1,#ff8800,0.4^^60.42961,22.26392~60.4343,22.28456~60.43499,22.29225~60.43245,22.29564~60.42894,22.29349~60.42506,22.27929~60.42531,22.26699 undefined^#FF0000,5,1,#ff8800,0.4^^60.42521,22.26577~60.42195,22.26877~60.41579,22.26733~60.41625,22.27877~60.42052,22.2783~60.42469,22.2762 undefined^#FF0000,5,1,#ff8800,0.4^^60.42288,22.24603~60.42536,22.26349~60.4219,22.26787~60.4157,22.26641~60.41536,22.2713~60.40943,22.26612~60.41382,22.25849 @@ -220,7 +218,6 @@ undefined^#FF0000,5,1,#ff8800,0.4^^60.57752,22.31255~60.56217,22.37125~60.59623,22.42342~60.63292,22.45499~60.65058,22.46426~60.65584,22.36526~60.63174,22.35328~60.59817,22.33307~60.58865,22.32559 undefined^#FF0000,5,1,#ff8800,0.4^^60.44566,22.32894~60.44287,22.33761~60.44321,22.34782~60.44984,22.34589~60.45284,22.34048~60.45192,22.3356~60.44968,22.33216 undefined^#FF0000,5,1,#ff8800,0.4^^60.44342,22.35014~60.44365,22.36593~60.45433,22.36259~60.4541,22.34633 -undefined^#FF0000,5,1,#ff8800,0.4^^60.45325,22.27598~60.45286,22.27984~60.45163,22.28199~60.45289,22.28662~60.45341,22.28622~60.45409,22.28811~60.4547,22.29174~60.4581,22.28897~60.45934,22.28666~60.45933,22.28296~60.45869,22.27967~60.4577,22.27773 undefined^#FF0000,5,1,#ff8800,0.4^^59.98508,22.40559~59.96861,22.46199~59.90874,22.41863~59.91541,22.38107 undefined^#FF0000,5,1,#ff8800,0.4^^60.18318,22.75921~60.16474,22.7853~60.14331,22.70053~60.1664,22.67258~60.18195,22.7181 undefined^#FF0000,5,1,#ff8800,0.4^^60.36619,22.69037~60.35583,22.75114~60.30695,22.70246~60.32315,22.59175~60.359,22.64749 @@ -228,4 +225,9 @@ undefined^#FF0000,5,1,#ff8800,0.4^^60.47333,22.01433~60.47077,22.02031~60.46786,22.01456~60.47116,22.00777 undefined^#FF0000,5,1,#ff8800,0.4^^60.41684,22.28808~60.41429,22.28833~60.41165,22.288~60.40885,22.28525~60.40811,22.2759~60.40868,22.27027~60.41208,22.2701~60.4155,22.27276 undefined^#FF0000,5,1,#ff8800,0.4^^60.40938,22.31293~60.40543,22.32123~60.4055,22.33379~60.40597,22.34177~60.40995,22.3419~60.41107,22.32617 +undefined^#FF0000,5,1,#ff8800,0.4^^60.39509,22.25658~60.40071,22.27487~60.39686,22.28173~60.38912,22.27937~60.39126,22.2647 +undefined^#FF0000,5,1,#ff8800,0.4^^60.45149,22.28207~60.45296,22.28687~60.45331,22.2863~60.45396,22.28784~60.4547,22.2914~60.45718,22.28964~60.45899,22.28822~60.45989,22.28723~60.46017,22.28231~60.45966,22.28067~60.45865,22.28021~60.45842,22.28321~60.45696,22.28289~60.4546,22.28215~60.45266,22.28019 +undefined^#FF0000,5,1,#ff8800,0.4^^60.45324,22.27609~60.45293,22.27966~60.45275,22.28014~60.45463,22.28203~60.45742,22.28287~60.45835,22.28304~60.45865,22.27854 +undefined^#FF0000,5,1,#ff8800,0.4^^60.44228,22.29847~60.44443,22.30868~60.43893,22.31718~60.43753,22.31481~60.43776,22.31424~60.43729,22.31155~60.43557,22.31207~60.43555,22.31654~60.43732,22.31509~60.4388,22.31754~60.43444,22.32246~60.43402,22.30368 +undefined^#FF0000,5,1,#ff8800,0.4^^60.43727,22.31164~60.4377,22.3142~60.43561,22.31633~60.43565,22.31219 @@@@@@
--- a/service.py Thu Jun 22 19:01:31 2017 +0300 +++ b/service.py Sat Jun 24 19:38:05 2017 +0300 @@ -7,6 +7,7 @@ from misc import * from busroute import reduce_schedule +import buses app = Flask(__name__) @@ -220,10 +221,19 @@ def static_file(path): return send_from_directory(path.join('static', path)) +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument('gtfs_zip_path') +parser.add_argument('profile_path') + if __name__ == '__main__': - from argparse import ArgumentParser - parser = ArgumentParser() parser.add_argument('-p', '--port', type = int, default = 5000) parser.add_argument('-d', '--debug', action = 'store_true') - args = parser.parse_args() + +args = parser.parse_args() +profile = ConfigParser() +profile.read(args.profile_path) +buses.load_buses(args.gtfs_zip_path, profile = profile) + +if __name__ == '__main__': app.run(debug = args.debug, port = args.port)
--- a/static/style.css Thu Jun 22 19:01:31 2017 +0300 +++ b/static/style.css Sat Jun 24 19:38:05 2017 +0300 @@ -1,6 +1,7 @@ * { font-family: FreeSans, helvetica, Arial, sans-serif; + font-weight: light; } body { @@ -44,7 +45,8 @@ { margin: auto; margin-bottom: 30pt; - min-width: 50%; + /*min-width: 50%;*/ + min-width: 85%; border: 1px solid gray; }
--- a/templates/cluster.html Thu Jun 22 19:01:31 2017 +0300 +++ b/templates/cluster.html Sat Jun 24 19:38:05 2017 +0300 @@ -22,6 +22,10 @@ { text-align: center; } + .sarake-määränpää + { + text-align: left; + } /* body {
--- a/tr/en.ini Thu Jun 22 19:01:31 2017 +0300 +++ b/tr/en.ini Sat Jun 24 19:38:05 2017 +0300 @@ -1,14 +1,16 @@ [paikat] -satama = ⚓ Harbor -kauppatori = City Centre -lentoasema = ✈ Airport -ylioppilaskylä = Student Village +satama = Harbor ⚓ +kauppatori = City centre +lentoasema = Airport ✈ +ylioppilaskylä = Student village kauppakeskus mylly = Mylly -raision keskusta = Raisio Centrum -naantalin keskusta = Naantali Centrum -linja-autoasema = Bus Station -rautatieasema = Railway Station +raision keskusta = Raisio +naantalin keskusta = Naantali +linja-autoasema = Bus station +rautatieasema = Railway station kaarinan keskusta = Kaarina +pernon telakka = Perno docks +kasarmialue = Barracks area [misc-text] right-now = now
--- a/tr/fi.ini Thu Jun 22 19:01:31 2017 +0300 +++ b/tr/fi.ini Sat Jun 24 19:38:05 2017 +0300 @@ -1,8 +1,8 @@ [paikat] Korpo = Korppoo Pargas = Parainen -lentoasema = ✈ Lentoasema -satama = ⚓ Satama +lentoasema = Lentoasema ✈ +satama = Satama ⚓ kauppakeskus mylly = Mylly kaarinan keskusta = Kaarina naantalin keskusta = Naantali
--- a/tr/sv.ini Thu Jun 22 19:01:31 2017 +0300 +++ b/tr/sv.ini Sat Jun 24 19:38:05 2017 +0300 @@ -1651,6 +1651,7 @@ kaistarniemi = Kaistarudden katariina = Katarina kauppatori = Salutorget +kasarmialue = Kasernen kerttuli = Gertrudsbacken koivula = Björkas konserttitalo = Konserthuset @@ -1665,7 +1666,7 @@ isokylä = Storby lauste = Laustis lauttaranta = Färjstranden -lentoasema = ✈ Flygplatsen +lentoasema = Flygplatsen ✈ liljalaakso = Liljedalen linja-autoasema = Linjebilstationen littoinen = Littois @@ -1696,7 +1697,7 @@ ruskon keskusta = Rusko centrum rymättylä = Rimito saramäki = Starrbacka -satama = ⚓ Hamnen +satama = Hamnen ⚓ skanssi = Skansen toijainen = Toijais tuomiokirkkotori = Domkyrkotorget @@ -1709,7 +1710,7 @@ vii kaupunginosa = VII stadsdelen vähä-heikkilä = Lillheikkilä yli-maaria = Övre S:t Marie -yliopistonmäki = Universitetsbacken +yliopisto = Universitet ylioppilaskylä = Studentbyn ylioppilaskylä-länsi = Västra Studentbyn ylioppilaskylä-itä = Östra Studentbyn