def runTool(outLinesFC, SQLDbase, combine_corridors): try: BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") ispy3 = sys.version_info >= (3, 0) # Derived inputs outGDB = os.path.dirname( outLinesFC) # Must be in fgdb. Validated in tool validation. # Create a guid to make sure temporary outputs have unique names. They should be deleted # when the tool completes, but this ensures they don't conflict with any existing feature # classes in the gdb and makes it easier to know what they are and delete them if they # don't automatically get deleted. guid = uuid.uuid4().hex outStopPairsFCName = "StopPairs_" + guid outStopPairsFC = os.path.join(outGDB, outStopPairsFCName) # Get the original overwrite output setting so we can reset it at the end. OverwriteOutput = arcpy.env.overwriteOutput # It's okay to overwrite stuff in this tool arcpy.env.overwriteOutput = True conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase) triproute_dict = BBB_SharedFunctions.MakeTripRouteDict() # ----- Initialize a dictionary of stop geometry ----- # Get the stops table (exclude parent stations and station entrances) c = conn.cursor() selectstoptablestmt = "SELECT stop_id, stop_lat, stop_lon, location_type FROM stops;" c.execute(selectstoptablestmt) # Initialize a dictionary of stop lat/lon # {stop_id: <stop geometry object>} in the output coordinate system stoplatlon_dict = {} for stop in c: stop_id = stop[0] stop_lat = stop[1] stop_lon = stop[2] location_type = stop[3] if location_type not in [0, '0', None, ""]: # Skip parent stations and station entrances continue pt = arcpy.Point() pt.X = float(stop_lon) pt.Y = float(stop_lat) # GTFS stop lat/lon is written in WGS1984 ptGeometry = arcpy.PointGeometry(pt, BBB_SharedFunctions.WGSCoords) stoplatlon_dict[stop_id] = ptGeometry # ----- Obtain schedule info from the stop_times.txt file and convert it to a line-based model ----- arcpy.AddMessage( "Obtaining and processing transit schedule and line information..." ) arcpy.AddMessage("(This will take a few minutes for large datasets.)") # Create a line-based schedule table c2 = conn.cursor() c2.execute("DROP TABLE IF EXISTS schedules;") c2.execute( "CREATE TABLE schedules (key TEXT, start_time REAL, end_time REAL, trip_id TEXT);" ) # Find pairs of directly-connected stops linefeature_dict = {} stoptimefetch = ''' SELECT trip_id, stop_id, arrival_time, departure_time FROM stop_times ORDER BY trip_id, stop_sequence ;''' c.execute(stoptimefetch) current_trip = None previous_stop = None start_time = None end_time = None for st in c: trip_id = st[0] stop_id = st[1] arrival_time = st[2] departure_time = st[3] if trip_id != current_trip: current_trip = trip_id previous_stop = stop_id start_time = departure_time # Start time of segment is the departure time from the stop continue start_stop = previous_stop end_stop = stop_id end_time = arrival_time SourceOIDkey = "%s , %s" % (start_stop, end_stop) if combine_corridors: # All trips between each pair of stops will be combined, regardless of route_id linefeature_dict[SourceOIDkey] = True else: # A separate line will be created for each separate route between the same two stops linefeature_dict[SourceOIDkey + " , " + triproute_dict[trip_id]] = True stmt = """INSERT INTO schedules (key, start_time, end_time, trip_id) VALUES ('%s', %s, %s, '%s');""" % ( SourceOIDkey, start_time, end_time, trip_id) c2.execute(stmt) previous_stop = stop_id start_time = departure_time conn.commit() c2.execute( "CREATE INDEX schedules_index_tripsstend ON schedules (trip_id, start_time, end_time);" ) conn.commit() # ----- Write pairs to a points feature class (this is intermediate and will NOT go into the final output) ----- # Create a points feature class for the point pairs. arcpy.management.CreateFeatureclass(outGDB, outStopPairsFCName, "POINT", "", "", "", BBB_SharedFunctions.WGSCoords) arcpy.management.AddField(outStopPairsFC, "stop_id", "TEXT") arcpy.management.AddField(outStopPairsFC, "pair_id", "TEXT") arcpy.management.AddField(outStopPairsFC, "sequence", "SHORT") # Add pairs of stops to the feature class in preparation for generating line features badStops = [] badkeys = [] with arcpy.da.InsertCursor( outStopPairsFC, ["SHAPE@", "stop_id", "pair_id", "sequence"]) as cur: # linefeature_dict = {"start_stop , end_stop , route_type": True} for SourceOIDkey in linefeature_dict: stopPair = SourceOIDkey.split(" , ") # {stop_id: [stop_lat, stop_lon]} try: stop1 = stopPair[0] stop1_geom = stoplatlon_dict[stop1] except KeyError: badStops.append(stop1) badkeys.append(SourceOIDkey) continue try: stop2 = stopPair[1] stop2_geom = stoplatlon_dict[stop2] except KeyError: badStops.append(stop2) badkeys.append(SourceOIDkey) continue cur.insertRow((stop1_geom, stop1, SourceOIDkey, 1)) cur.insertRow((stop2_geom, stop2, SourceOIDkey, 2)) if badStops: badStops = list(set(badStops)) if ispy3: badStops_str = str(badStops) else: badStops_str = unicode(badStops) arcpy.AddWarning( "Your stop_times.txt lists times for the following \ stops which are not included in your stops.txt file. Schedule information for \ these stops will be ignored. " + badStops_str) # Remove these entries from the linefeatures dictionary so it doesn't cause false records later if badkeys: badkeys = list(set(badkeys)) for key in badkeys: del linefeature_dict[key] # ----- Generate lines between all stops (for the final output) ----- arcpy.management.PointsToLine(outStopPairsFC, outLinesFC, "pair_id", "sequence") if not combine_corridors: arcpy.management.AddField(outLinesFC, "route_id", "TEXT") # We don't need the points for anything anymore, so delete them. arcpy.management.Delete(outStopPairsFC) # Clean up lines with 0 length. They will just produce build errors and # are not valuable for visualization anyway. expression = """"Shape_Length" = 0""" with arcpy.da.UpdateCursor(outLinesFC, ["pair_id"], expression) as cur2: for row in cur2: del linefeature_dict[row[0]] cur2.deleteRow() if not combine_corridors: with arcpy.da.UpdateCursor(outLinesFC, ["pair_id", "route_id"]) as cur4: for row in cur4: row[1] = row[0].split(" , ")[2] cur4.updateRow(row) # ----- Finish up. ----- conn.close() arcpy.AddMessage("Finished!") arcpy.AddMessage("Your transit lines template feature class is:") arcpy.AddMessage("- " + outLinesFC) except BBB_SharedFunctions.CustomError: arcpy.AddError("Failed to generate transit lines.") pass except: arcpy.AddError("Failed to generate transit lines.") raise finally: # Reset the overwrite output to the user's original setting arcpy.env.overwriteOutput = OverwriteOutput
def runTool(step1LinesFC, SQLDbase, linesFC, day, start_time, end_time): try: # ------ Get input parameters and set things up. ----- BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") try: # If it was a feature layer, it will have a data source property step1LinesFC = step1LinesFC.dataSource except: # Otherwise, assume it was a catalog path and use as is pass # GTFS SQL dbase - must be created ahead of time. BBB_SharedFunctions.ConnectToSQLDatabase(SQLDbase) Specific, day = BBB_SharedFunctions.CheckSpecificDate(day) start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds( start_time, end_time) # Does the user want to count arrivals or departures at the stops? DepOrArr = "departure_time" # ----- Prepare output file ----- try: arcpy.management.Copy(step1LinesFC, linesFC) except: arcpy.AddError( "Error copying template lines feature class to output %s," % linesFC) raise # ----- Query the GTFS data to count the trips on each line segment ----- try: arcpy.AddMessage( "Calculating the number of transit trips available during the time window..." ) # Get a dictionary of {line_key: [[trip_id, start_time, end_time]]} for our time window linetimedict = BBB_SharedFunctions.CountTripsOnLines( day, start_sec, end_sec, DepOrArr, Specific) except: arcpy.AddError( "Error counting arrivals or departures at during time window.") raise # ----- Write to output ----- try: arcpy.AddMessage("Writing output data...") combine_corridors = "route_id" not in [ f.name for f in arcpy.ListFields(linesFC) ] triproute_dict = None if not combine_corridors: triproute_dict = BBB_SharedFunctions.MakeTripRouteDict() arcpy.management.AddField(linesFC, "NumTrips", "SHORT") arcpy.management.AddField(linesFC, "NumTripsPerHr", "DOUBLE") arcpy.management.AddField(linesFC, "MaxWaitTime", "SHORT") arcpy.management.AddField(linesFC, "AvgHeadway", "SHORT") with arcpy.da.UpdateCursor(linesFC, [ "pair_id", "NumTrips", "NumTripsPerHr", "MaxWaitTime", "AvgHeadway" ]) as ucursor: for row in ucursor: NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway = \ BBB_SharedFunctions.RetrieveStatsForLines( str(row[0]), linetimedict, start_sec, end_sec, combine_corridors, triproute_dict) row[1] = NumTrips row[2] = NumTripsPerHr row[3] = MaxWaitTime row[4] = AvgHeadway ucursor.updateRow(row) except: arcpy.AddError("Error writing to output.") raise arcpy.AddMessage("Finished!") arcpy.AddMessage("Your output is located at " + linesFC) except BBB_SharedFunctions.CustomError: arcpy.AddError("Failed to count trips on lines.") pass except: arcpy.AddError("Failed to count trips on lines.") raise
You have ArcGIS Pro version %s." % BBB_SharedFunctions.ArcVersion) raise CustomError if BBB_SharedFunctions.ArcVersion == "10.0": arcpy.AddError( "You must have ArcGIS 10.1 or higher (or ArcGIS Pro) to run this \ tool. You have ArcGIS version %s." % BBB_SharedFunctions.ArcVersion) raise CustomError # ----- Connect to SQL locally for further queries and entries ----- # Connect to the SQL database conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase) # ----- Make dictionary of {trip_id: route_id} ----- BBB_SharedFunctions.MakeTripRouteDict() # ----- Initialize a dictionary of stop geometry ----- # Get the stops table (exclude parent stations and station entrances) c = conn.cursor() selectstoptablestmt = "SELECT stop_id, stop_lat, stop_lon, location_type FROM stops;" c.execute(selectstoptablestmt) # Initialize a dictionary of stop lat/lon # {stop_id: <stop geometry object>} in the output coordinate system stoplatlon_dict = {} for stop in c: stop_id = stop[0] stop_lat = stop[1] stop_lon = stop[2]