1# -*- coding: utf-8 -*- 2# This file is part of Gtfslib-python. 3# 4# Gtfslib-python is free software: you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation, either version 3 of the License, or 7# (at your option) any later version. 8# 9# Gtfslib-python is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with gtfslib-python. If not, see <http://www.gnu.org/licenses/>. 16""" 17@author: Laurent GRÉGOIRE <laurent.gregoire@mecatran.com> 18""" 19 20import unicodedata 21import shapefile 22from gtfslib.spatial import SpatialClusterizer 23from collections import defaultdict 24 25class ShapefileExport(object): 26 """ 27 Export data (stops, hops) to ESRI shapefile. 28 Include frequency of use for each element 29 * number of trips 30 * number of trips x days 31 Note: Usually the trips x days is a better usage metric as 32 trips can be active on various number of days. If you want 33 to compute the average number of trips per day, divide the 34 result by the number of days (you can use date filtering). 35 36 Parameters: 37 --cluster=<dist> Cluster stops closer than <dist> meters 38 --stopshp=<file> Output stops to given shapefile 39 --hopshp=<file> Output hops to given shapefile 40 """ 41 42 def __init__(self): 43 pass 44 45 def remove_accents(self, strd): 46 nfkd_form = unicodedata.normalize('NFKD', strd) 47 only_ascii = nfkd_form.encode('ASCII', 'ignore') 48 return only_ascii 49 50 def run(self, context, stopshp=None, hopshp=None, cluster=0, **kwargs): 51 cluster_meters = float(cluster) 52 if stopshp is None and hopshp is None: 53 print("Nothing to generate! Bailing out") 54 return 55 56 print("Loading stops...") 57 stops = set() 58 sc = SpatialClusterizer(cluster_meters) 59 for stop in context.dao().stops(fltr=context.args.filter): 60 sc.add_point(stop) 61 stops.add(stop) 62 print("Loaded %d stops. Clusterize..." % (len(stops))) 63 sc.clusterize() 64 print("Aggregated in %d clusters" % (len(sc.clusters()))) 65 66 print("Loading calendar dates") 67 dates = set(context.dao().calendar_dates_date(fltr=context.args.filter)) 68 print("Loaded %d dates" % (len(dates))) 69 70 print("Computing stop and hop trip count...") 71 hop_tripcount = defaultdict(lambda: [0, 0]) 72 clu_tripcount = defaultdict(lambda: [0, 0]) 73 ntrips = 0 74 for trip in context.dao().trips(fltr=context.args.filter, prefetch_stop_times=True, prefetch_stops=True, prefetch_calendars=True): 75 # Compute the number of days the trip is running 76 # RESTRICTED ON THE FILTERED DATES 77 ndays = len([ date for date in trip.calendar.dates if date.as_date() in dates ]) 78 for st1, st2 in trip.hops(): 79 cluster1 = sc.cluster_of(st1.stop) 80 cluster2 = sc.cluster_of(st2.stop) 81 if cluster1 == cluster2: 82 pass 83 key = (cluster1, cluster2) 84 hop_tripcount[key][0] += 1 85 hop_tripcount[key][1] += ndays 86 clu_tripcount[cluster1][0] += 1 87 clu_tripcount[cluster1][1] += ndays 88 ntrips += 1 89 if ntrips % 1000 == 0: 90 print("%d trips..." % ntrips) 91 92 if stopshp: 93 print("Generating stops cluster shapefile...") 94 stopshpwrt = shapefile.Writer(shapefile.POINT) 95 stopshpwrt.field("id", "N") 96 stopshpwrt.field("ids", "C", 100) 97 stopshpwrt.field("name", "C", 200) 98 stopshpwrt.field("ndep", "N") 99 stopshpwrt.field("ndepday", "N") 100 for cluster, (dep_count, depday_count) in clu_tripcount.items(): 101 stopshpwrt.point(cluster.lon(), cluster.lat()) # X,Y ? 102 ids = cluster.aggregate(lambda s: s.stop_id, sep=';') 103 names = cluster.aggregate(lambda s: s.stop_name, sep=';') 104 stopshpwrt.record(cluster.id, self.remove_accents(ids), 105 self.remove_accents(names), 106 dep_count, depday_count) 107 stopshpwrt.save(stopshp) 108 109 if hopshp: 110 print("Generating hop shapefile...") 111 hopshpwrt = shapefile.Writer(shapefile.POLYLINE) 112 hopshpwrt.field("from_id", "N") 113 hopshpwrt.field("from_name", "C", 200) 114 hopshpwrt.field("to_id", "N") 115 hopshpwrt.field("to_name", "C", 200) 116 hopshpwrt.field("name", "C", 200) 117 hopshpwrt.field("ntrip", "N") 118 hopshpwrt.field("ntripday", "N") 119 for (c1, c2), (trip_count, tripday_count) in hop_tripcount.items(): 120 c1name = c1.aggregate(lambda s: s.stop_name, sep=';') 121 c2name = c2.aggregate(lambda s: s.stop_name, sep=';') 122 hopshpwrt.line(parts=[[[c1.lon(), c1.lat()], [c2.lon(), c2.lat()]]]) 123 hopshpwrt.record(c1.id, self.remove_accents(c1name), c2.id, 124 self.remove_accents(c2name), 125 self.remove_accents(c1name + " -> " + c2name), 126 trip_count, tripday_count) 127 hopshpwrt.save(hopshp) 128