ODCursor = arcpy.da.SearchCursor(linesSubLayer, [inLocUniqueID_qualified, "stop_id"]) for row in ODCursor: PointsAndStops.setdefault(str(row[0]), []).append(str(row[1])) del ODCursor except: arcpy.AddError("Error creating OD matrix between stops and input points.") raise #----- Query the GTFS data to count the trips at each stop ----- try: arcpy.AddMessage("Calculating the number of transit trips available during the time window...") # Get a dictionary of stop times in our time window {stop_id: [[trip_id, stop_time]]} stoptimedict = BBB_SharedFunctions.CountTripsAtStops(day, start_sec, end_sec, DepOrArr, Specific) except: arcpy.AddError("Error calculating the number of transit trips available during the time window.") raise # ----- Generate output data ----- try: arcpy.AddMessage("Writing output data...") arcpy.management.CopyFeatures(inPointsLayer, outFile) # Add a field to the output file for number of trips and num trips / hour. if ".shp" in outFilename: arcpy.management.AddField(outFile, "NumTrips", "SHORT") arcpy.management.AddField(outFile, "TripsPerHr", "DOUBLE")
def runTool(inStep1GDB, outFile, day, start_time, end_time, DepOrArrChoice): try: # ----- Set up the run ----- try: BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") # Get the files from Step 1 to work with. # Step1_GTFS.sql and Step1_FlatPolys must exist in order for the tool to run. # Their existence is checked in the GUI validation logic. FlatPolys = os.path.join(inStep1GDB, "Step1_FlatPolys") SQLDbase = os.path.join(inStep1GDB, "Step1_GTFS.sql") # Connect to the SQL database conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase) c = BBB_SharedFunctions.c = conn.cursor() # Output file designated by user outDir = os.path.dirname(outFile) outFilename = os.path.basename(outFile) Specific, day = BBB_SharedFunctions.CheckSpecificDate(day) start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds( start_time, end_time) # Will we calculate the max wait time? This slows down the calculation, so leave it optional. CalcWaitTime = True # It's okay to overwrite stuff. OverwriteOutput = arcpy.env.overwriteOutput # Get the orignal value so we can reset it. arcpy.env.overwriteOutput = True except: arcpy.AddError("Error setting up run.") raise #----- Query the GTFS data to count the trips at each stop ----- try: arcpy.AddMessage( "Counting transit trips during the time window...") # Get a dictionary of stop times in our time window {stop_id: [[trip_id, stop_time]]} stoptimedict = BBB_SharedFunctions.CountTripsAtStops( day, start_sec, end_sec, BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice), Specific) except: arcpy.AddError( "Failed to count transit trips during the time window.") raise #----- Find which stops serve each polygon ----- try: arcpy.AddMessage( "Retrieving list of stops associated with each polygon...") # Find the stop_ids associated with each flattened polygon and put them in # a dictionary. {ORIG_FID: [stop_id, stop_id,...]} stackedpointdict = {} GetStackedPtsStmt = "SELECT * FROM StackedPoints" c.execute(GetStackedPtsStmt) for PolyFID in c: stackedpointdict.setdefault(PolyFID[0], []).append(str(PolyFID[1])) except: arcpy.AddError( "Error retrieving list of stops associated with each polygon.") raise # ----- Generate output data ----- try: arcpy.AddMessage("Writing output data...") # Create the output file from FlatPolys. We don't want to overwrite the # original Step 1 template file. arcpy.management.CopyFeatures(FlatPolys, outFile) badpolys = [] if ".shp" in outFilename: ucursor = arcpy.da.UpdateCursor(outFile, [ "PolyID", "NumTrips", "NumTripsPe", "NumStopsIn", "MaxWaitTim" ]) else: ucursor = arcpy.da.UpdateCursor(outFile, [ "PolyID", "NumTrips", "NumTripsPerHr", "NumStopsInRange", "MaxWaitTime" ]) for row in ucursor: try: ImportantStops = stackedpointdict[int(row[0])] except KeyError: # If we got a KeyError here, then an output polygon never # got a point associated with it, probably the result of a # geometry problem because of the large cluster tolerance # used to generate the polygons in Step 1. Just skip this # polygon and alert the user. badpolys.append(row[0]) continue NumTrips, NumTripsPerHr, NumStopsInRange, MaxWaitTime = \ BBB_SharedFunctions.RetrieveStatsForSetOfStops( ImportantStops, stoptimedict, CalcWaitTime, start_sec, end_sec) row[1] = NumTrips row[2] = NumTripsPerHr row[3] = NumStopsInRange if ".shp" in outFilename and MaxWaitTime == None: row[4] = -1 else: row[4] = MaxWaitTime ucursor.updateRow(row) if badpolys: arcpy.AddWarning( "Warning! BetterBusBuffers could not calculate trip \ statistics for one or more polygons due to a geometry issue. These polygons will \ appear in your output data, but all output values will be null. Bad polygon \ PolyID values: " + str(badpolys)) except: arcpy.AddMessage("Error writing output.") raise arcpy.AddMessage("Finished!") arcpy.AddMessage("Your output is located at " + outFile) except CustomError: arcpy.AddError("Error counting transit trips in polygons.") pass except: arcpy.AddError("Error counting transit trips in polygons.") raise finally: # Reset overwriteOutput to what it was originally. arcpy.env.overwriteOutput = OverwriteOutput
def runTool(outFile, SQLDbase, inPointsLayer, inLocUniqueID, day, start_time, end_time, inNetworkDataset, imp, BufferSize, restrictions, DepOrArrChoice): try: # Source FC names are not prepended to field names. arcpy.env.qualifiedFieldNames = False # It's okay to overwrite in-memory stuff. OverwriteOutput = arcpy.env.overwriteOutput # Get the orignal value so we can reset it. arcpy.env.overwriteOutput = True BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") ProductName = BBB_SharedFunctions.ProductName BBB_SharedFunctions.CheckWorkspace() BBB_SharedFunctions.CheckOutNALicense() BBB_SharedFunctions.ConnectToSQLDatabase(SQLDbase) Specific, day = BBB_SharedFunctions.CheckSpecificDate(day) start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds( start_time, end_time) # Will we calculate the max wait time? CalcWaitTime = True impedanceAttribute = BBB_SharedFunctions.CleanUpImpedance(imp) # Hard-wired OD variables ExcludeRestricted = "EXCLUDE" PathShape = "NO_LINES" accumulate = "" uturns = "ALLOW_UTURNS" hierarchy = "NO_HIERARCHY" # Output file designated by user outDir = os.path.dirname(outFile) outFilename = os.path.basename(outFile) inLocUniqueID = BBB_SharedFunctions.HandleOIDUniqueID( inPointsLayer, inLocUniqueID) inLocUniqueID_qualified = inLocUniqueID + "_Input" arcpy.AddMessage("Run set up successfully.") # ----- Create a feature class of stops ------ try: arcpy.AddMessage("Getting GTFS stops...") tempstopsname = "Temp_Stops" if ".shp" in outFilename: tempstopsname += ".shp" StopsLayer, StopList = BBB_SharedFunctions.MakeStopsFeatureClass( os.path.join(outDir, tempstopsname)) except: arcpy.AddError("Error creating feature class of GTFS stops.") raise #----- Create OD Matrix between stops and user's points ----- try: arcpy.AddMessage("Creating OD matrix between points and stops...") arcpy.AddMessage( "(This step could take a while for large datasets or buffer sizes.)" ) # Name to refer to OD matrix layer outNALayer_OD = "ODMatrix" # ODLayer is the NA Layer object returned by getOutput(0) ODLayer = arcpy.na.MakeODCostMatrixLayer( inNetworkDataset, outNALayer_OD, impedanceAttribute, BufferSize, "", accumulate, uturns, restrictions, hierarchy, "", PathShape).getOutput(0) # To refer to the OD sublayers, get the sublayer names. This is essential for localization. naSubLayerNames = arcpy.na.GetNAClassNames(ODLayer) points = naSubLayerNames["Origins"] stops = naSubLayerNames["Destinations"] # Add a field for stop_id as a unique identifier for stops. arcpy.na.AddFieldToAnalysisLayer(outNALayer_OD, stops, "stop_id", "TEXT") # Specify the field mappings for the stop_id field. fieldMappingStops = arcpy.na.NAClassFieldMappings(ODLayer, stops) fieldMappingStops["Name"].mappedFieldName = "stop_id" fieldMappingStops["stop_id"].mappedFieldName = "stop_id" # Add the GTFS stops as locations for the analysis. arcpy.na.AddLocations(outNALayer_OD, stops, StopsLayer, fieldMappingStops, "500 meters", "", "", "", "", "", "", ExcludeRestricted) # Clear out the memory because we don't need this anymore. arcpy.management.Delete(StopsLayer) # Add a field for unique identifier for points. arcpy.na.AddFieldToAnalysisLayer(outNALayer_OD, points, inLocUniqueID_qualified, "TEXT") # Specify the field mappings for the unique id field. fieldMappingPoints = arcpy.na.NAClassFieldMappings(ODLayer, points) fieldMappingPoints["Name"].mappedFieldName = inLocUniqueID fieldMappingPoints[ inLocUniqueID_qualified].mappedFieldName = inLocUniqueID # Add the input points as locations for the analysis. arcpy.na.AddLocations(outNALayer_OD, points, inPointsLayer, fieldMappingPoints, "500 meters", "", "", "", "", "", "", ExcludeRestricted) # Solve the OD matrix. try: arcpy.na.Solve(outNALayer_OD) except: errs = arcpy.GetMessages(2) if "No solution found" in errs: impunits = imp.split(" (Units: ")[1].split(")")[0] arcpy.AddError( "No transit stops were found within a %s %s walk of any of your input points. \ Consequently, there is no transit service available to your input points, so no output will be generated." % (str(BufferSize), impunits)) else: arcpy.AddError( "Failed to calculate travel time or distance between transit stops and input points. OD Cost Matrix error messages:" ) arcpy.AddError(errs) raise BBB_SharedFunctions.CustomError # Make layer objects for each sublayer we care about. if ProductName == 'ArcGISPro': naSubLayerNames = arcpy.na.GetNAClassNames(ODLayer) subLayerDict = dict( (lyr.name, lyr) for lyr in ODLayer.listLayers()) subLayers = {} for subL in naSubLayerNames: subLayers[subL] = subLayerDict[naSubLayerNames[subL]] else: subLayers = dict( (lyr.datasetName, lyr) for lyr in arcpy.mapping.ListLayers(ODLayer)[1:]) linesSubLayer = subLayers["ODLines"] pointsSubLayer = subLayers["Origins"] stopsSubLayer = subLayers["Destinations"] # Get the OID fields, just to be thorough desc1 = arcpy.Describe(pointsSubLayer) points_OID = desc1.OIDFieldName desc2 = arcpy.Describe(stopsSubLayer) stops_OID = desc2.OIDFieldName # Join polygons layer with input facilities to port over the stop_id arcpy.management.JoinField(linesSubLayer, "OriginID", pointsSubLayer, points_OID, [inLocUniqueID_qualified]) arcpy.management.JoinField(linesSubLayer, "DestinationID", stopsSubLayer, stops_OID, ["stop_id"]) # Use searchcursor on lines to find the stops that are reachable from points. global PointsAndStops # PointsAndStops = {LocID: [stop_1, stop_2, ...]} PointsAndStops = {} ODCursor = arcpy.da.SearchCursor( linesSubLayer, [inLocUniqueID_qualified, "stop_id"]) for row in ODCursor: PointsAndStops.setdefault(str(row[0]), []).append(str(row[1])) del ODCursor except: arcpy.AddError( "Error creating OD matrix between stops and input points.") raise #----- Query the GTFS data to count the trips at each stop ----- try: arcpy.AddMessage( "Calculating the number of transit trips available during the time window..." ) # Get a dictionary of stop times in our time window {stop_id: [[trip_id, stop_time]]} stoptimedict = BBB_SharedFunctions.CountTripsAtStops( day, start_sec, end_sec, BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice), Specific) except: arcpy.AddError( "Error calculating the number of transit trips available during the time window." ) raise # ----- Generate output data ----- try: arcpy.AddMessage("Writing output data...") arcpy.management.CopyFeatures(inPointsLayer, outFile) # Add a field to the output file for number of trips and num trips / hour. if ".shp" in outFilename: arcpy.management.AddField(outFile, "NumTrips", "SHORT") arcpy.management.AddField(outFile, "TripsPerHr", "DOUBLE") arcpy.management.AddField(outFile, "NumStops", "SHORT") arcpy.management.AddField(outFile, "MaxWaitTm", "SHORT") else: arcpy.management.AddField(outFile, "NumTrips", "SHORT") arcpy.management.AddField(outFile, "NumTripsPerHr", "DOUBLE") arcpy.management.AddField(outFile, "NumStopsInRange", "SHORT") arcpy.management.AddField(outFile, "MaxWaitTime", "SHORT") if ".shp" in outFilename: ucursor = arcpy.da.UpdateCursor(outFile, [ inLocUniqueID[0:10], "NumTrips", "TripsPerHr", "NumStops", "MaxWaitTm" ]) else: ucursor = arcpy.da.UpdateCursor(outFile, [ inLocUniqueID, "NumTrips", "NumTripsPerHr", "NumStopsInRange", "MaxWaitTime" ]) for row in ucursor: try: ImportantStops = PointsAndStops[str(row[0])] except KeyError: # This point had no stops in range ImportantStops = [] NumTrips, NumTripsPerHr, NumStopsInRange, MaxWaitTime =\ BBB_SharedFunctions.RetrieveStatsForSetOfStops( ImportantStops, stoptimedict, CalcWaitTime, start_sec, end_sec) row[1] = NumTrips row[2] = NumTripsPerHr row[3] = NumStopsInRange if ".shp" in outFilename and MaxWaitTime == None: row[4] = -1 else: row[4] = MaxWaitTime ucursor.updateRow(row) except: arcpy.AddError("Error writing output.") raise arcpy.AddMessage("Done!") arcpy.AddMessage("Output files written:") arcpy.AddMessage("- " + outFile) except BBB_SharedFunctions.CustomError: arcpy.AddError("Error counting transit trips at input locations.") pass except: arcpy.AddError("Error counting transit trips at input locations.") raise finally: # Reset overwriteOutput to what it was originally. arcpy.env.overwriteOutput = OverwriteOutput
def runTool(outFile, SQLDbase, inPointsLayer, inLocUniqueID, day, start_time, end_time, BufferSize, BufferUnits, DepOrArrChoice, username, password): def runOD(Points, Stops): # Call the OD Cost Matrix service for this set of chunks result = ODservice.GenerateOriginDestinationCostMatrix( Points, Stops, TravelMode, Distance_Units=BufferUnits, Cutoff=BufferSize, Origin_Destination_Line_Shape=PathShape) # Check the status of the result object every 0.5 seconds # until it has a value of 4(succeeded) or greater while result.status < 4: time.sleep(0.5) # Print any warning or error messages returned from the tool result_severity = result.maxSeverity if result_severity == 2: errors = result.getMessages(2) if "No solution found." in errors: # No destinations were found for the origins, which probably just means they were too far away. pass else: arcpy.AddError("An error occured when running the tool") arcpy.AddError(result.getMessages(2)) raise BBB_SharedFunctions.CustomError elif result_severity == 1: arcpy.AddWarning("Warnings were returned when running the tool") arcpy.AddWarning(result.getMessages(1)) # Get the resulting OD Lines and store the stops that are reachable from points. if result_severity != 2: linesSubLayer = result.getOutput(1) with arcpy.da.SearchCursor( linesSubLayer, ["OriginOID", "DestinationOID"]) as ODCursor: for row in ODCursor: UID = pointsOIDdict[row[0]] SID = stopOIDdict[row[1]] PointsAndStops.setdefault(str(UID), []).append(str(SID)) try: # Source FC names are not prepended to field names. arcpy.env.qualifiedFieldNames = False # It's okay to overwrite in-memory stuff. OverwriteOutput = arcpy.env.overwriteOutput # Get the orignal value so we can reset it. arcpy.env.overwriteOutput = True BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") BBB_SharedFunctions.ConnectToSQLDatabase(SQLDbase) Specific, day = BBB_SharedFunctions.CheckSpecificDate(day) start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds( start_time, end_time) # Distance between stops and points BufferSize_padded = BufferSize + (.2 * BufferSize) BufferLinearUnit = str(BufferSize_padded) + " " + BufferUnits # Will we calculate the max wait time? CalcWaitTime = True # Output file designated by user outDir = os.path.dirname(outFile) outFilename = os.path.basename(outFile) ispgdb = "esriDataSourcesGDB.AccessWorkspaceFactory" in arcpy.Describe( outDir).workspaceFactoryProgID inLocUniqueID = BBB_SharedFunctions.HandleOIDUniqueID( inPointsLayer, inLocUniqueID) # ----- Prepare OD service ----- try: arcpy.AddMessage( "Obtaining credentials for and information about OD Cost Matrix service..." ) # Hard-wired OD variables TravelMode = "Walking Distance" PathShape = "None" OD_service_name = "World/OriginDestinationCostMatrix" Utility_service_name = "World/Utilities" # Get the credentials from the signed in user and import the service if username and password: ODservice = BBB_SharedFunctions.import_AGOLservice( OD_service_name, username=username, password=password) Utilityservice = BBB_SharedFunctions.import_AGOLservice( Utility_service_name, username=username, password=password) else: credentials = arcpy.GetSigninToken() if not credentials: arcpy.AddError( "Please sign into ArcGIS Online or pass a username and password to the tool." ) raise BBB_SharedFunctions.CustomError token = credentials["token"] referer = credentials["referer"] ODservice = BBB_SharedFunctions.import_AGOLservice( OD_service_name, token=token, referer=referer) Utilityservice = BBB_SharedFunctions.import_AGOLservice( Utility_service_name, token=token, referer=referer) # Get the service limits from the OD service (how many origins and destinations allowed) utilresult = Utilityservice.GetToolInfo( "asyncODCostMatrix", "GenerateOriginDestinationCostMatrix") utilresultstring = utilresult.getOutput(0) utilresultjson = json.loads(utilresultstring) origin_limit = int( utilresultjson['serviceLimits']['maximumDestinations']) destination_limit = int( utilresultjson['serviceLimits']['maximumOrigins']) except: arcpy.AddError( "Failed to obtain credentials for and information about OD Cost Matrix service." ) raise # ----- Create a feature class of stops ------ try: arcpy.AddMessage("Getting GTFS stops...") tempstopsname = "Temp_Stops" StopsLayer, StopList = BBB_SharedFunctions.MakeStopsFeatureClass( os.path.join(outDir, tempstopsname)) # Select only the stops within a reasonable distance of points to reduce problem size arcpy.management.MakeFeatureLayer(StopsLayer, "StopsToRemove") arcpy.management.SelectLayerByLocation( "StopsToRemove", "WITHIN_A_DISTANCE_GEODESIC", inPointsLayer, BufferLinearUnit, invert_spatial_relationship="INVERT") arcpy.management.DeleteRows("StopsToRemove") arcpy.management.Delete("StopsToRemove") # Make Feature Layer of stops to use later arcpy.management.MakeFeatureLayer(StopsLayer, "StopsLayer") stopsOID = arcpy.Describe("StopsLayer").OIDFieldName except: arcpy.AddError("Error creating feature class of GTFS stops.") raise # ----- Prepare input data ----- try: arcpy.AddMessage("Preparing input points...") # Select only the points within a reasonable distance of stops to reduce problem size temppointsname = outFilename + "_Temp" relevantPoints = os.path.join(outDir, temppointsname) arcpy.management.MakeFeatureLayer(inPointsLayer, "PointsToKeep") arcpy.management.SelectLayerByLocation( "PointsToKeep", "WITHIN_A_DISTANCE_GEODESIC", StopsLayer, BufferLinearUnit) num_points = int( arcpy.management.GetCount("PointsToKeep").getOutput(0)) # If the number of points is large, sort them spatially for smart chunking if num_points > origin_limit: shapeFieldName = arcpy.Describe("PointsToKeep").shapeFieldName arcpy.management.Sort("PointsToKeep", relevantPoints, shapeFieldName, "PEANO") # Otherwise, just copy them. else: arcpy.management.CopyFeatures("PointsToKeep", relevantPoints) arcpy.management.Delete("PointsToKeep") # Store OIDs in a dictionary for later joining pointsOIDdict = {} # {OID: inLocUniqueID} with arcpy.da.SearchCursor(relevantPoints, ["OID@", inLocUniqueID]) as cur: for row in cur: pointsOIDdict[row[0]] = row[1] relevantpointsOID = arcpy.Describe(relevantPoints).OIDFieldName except: arcpy.AddError("Error preparing input points for analysis.") raise #----- Create OD Matrix between stops and user's points ----- try: arcpy.AddMessage("Creating OD matrix between points and stops...") arcpy.AddMessage( "(This step could take a while for large datasets or buffer sizes.)" ) global PointsAndStops # PointsAndStops = {LocID: [stop_1, stop_2, ...]} PointsAndStops = {} # Chunk the points to fit the service limits and loop through chunks points_numchunks = int(math.ceil(float(num_points) / origin_limit)) points_chunkstart = 0 points_chunkend = origin_limit current_chunk = 0 for x in range(0, points_numchunks): current_chunk += 1 arcpy.AddMessage("Handling input points chunk %i of %i" % (current_chunk, points_numchunks)) # Select only the points belonging to this chunk points_chunk = sorted( pointsOIDdict.keys())[points_chunkstart:points_chunkend] points_chunkstart = points_chunkend points_chunkend = points_chunkstart + origin_limit if ispgdb: points_selection_query = '[{0}] IN ({1})'.format( relevantpointsOID, ','.join(map(str, points_chunk))) else: points_selection_query = '"{0}" IN ({1})'.format( relevantpointsOID, ','.join(map(str, points_chunk))) arcpy.MakeFeatureLayer_management(relevantPoints, "PointsLayer", points_selection_query) # Select only the stops within the safe buffer of these points arcpy.management.SelectLayerByLocation( "StopsLayer", "WITHIN_A_DISTANCE_GEODESIC", "PointsLayer", BufferLinearUnit) num_stops = int( arcpy.GetCount_management("StopsLayer").getOutput(0)) stopOIDdict = {} # {OID: stop_id} with arcpy.da.SearchCursor("StopsLayer", ["OID@", "stop_id"]) as cur: for row in cur: stopOIDdict[row[0]] = row[1] # If the number of stops in range exceeds the destination limit, we have to chunk these as well. if num_stops > destination_limit: stops_numchunks = int( math.ceil(float(num_stops) / destination_limit)) stops_chunkstart = 0 stops_chunkend = destination_limit for x in range(0, stops_numchunks): stops_chunk = sorted(stopOIDdict.keys() )[stops_chunkstart:stops_chunkend] stops_chunkstart = stops_chunkend stops_chunkend = stops_chunkstart + destination_limit if ispgdb: stops_selection_query = '[{0}] IN ({1})'.format( stopsOID, ','.join(map(str, stops_chunk))) else: stops_selection_query = '"{0}" IN ({1})'.format( stopsOID, ','.join(map(str, stops_chunk))) arcpy.MakeFeatureLayer_management( "StopsLayer", "StopsLayer_Chunk", stops_selection_query) runOD("PointsLayer", "StopsLayer_Chunk") arcpy.management.Delete("StopsLayer_Chunk") # Otherwise, just run them all. else: runOD("PointsLayer", "StopsLayer") # Clean up arcpy.management.Delete("StopsLayer") arcpy.management.Delete("PointsLayer") arcpy.management.Delete(StopsLayer) arcpy.management.Delete(relevantPoints) except: arcpy.AddError( "Error creating OD matrix between stops and input points.") raise #----- Query the GTFS data to count the trips at each stop ----- try: arcpy.AddMessage( "Calculating the number of transit trips available during the time window..." ) # Get a dictionary of stop times in our time window {stop_id: [[trip_id, stop_time]]} stoptimedict = BBB_SharedFunctions.CountTripsAtStops( day, start_sec, end_sec, BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice), Specific) except: arcpy.AddError( "Error calculating the number of transit trips available during the time window." ) raise # ----- Generate output data ----- try: arcpy.AddMessage("Writing output data...") arcpy.management.CopyFeatures(inPointsLayer, outFile) # Add a field to the output file for number of trips and num trips / hour. arcpy.management.AddField(outFile, "NumTrips", "SHORT") arcpy.management.AddField(outFile, "NumTripsPerHr", "DOUBLE") arcpy.management.AddField(outFile, "NumStopsInRange", "SHORT") arcpy.management.AddField(outFile, "MaxWaitTime", "SHORT") with arcpy.da.UpdateCursor(outFile, [ inLocUniqueID, "NumTrips", "NumTripsPerHr", "NumStopsInRange", "MaxWaitTime" ]) as ucursor: for row in ucursor: try: ImportantStops = PointsAndStops[str(row[0])] except KeyError: # This point had no stops in range ImportantStops = [] NumTrips, NumTripsPerHr, NumStopsInRange, MaxWaitTime =\ BBB_SharedFunctions.RetrieveStatsForSetOfStops( ImportantStops, stoptimedict, CalcWaitTime, start_sec, end_sec) row[1] = NumTrips row[2] = NumTripsPerHr row[3] = NumStopsInRange row[4] = MaxWaitTime ucursor.updateRow(row) except: arcpy.AddError("Error writing output.") raise arcpy.AddMessage("Done!") arcpy.AddMessage("Output files written:") arcpy.AddMessage("- " + outFile) except BBB_SharedFunctions.CustomError: arcpy.AddError("Error counting transit trips at input locations.") pass except: arcpy.AddError("Error counting transit trips at input locations.") raise finally: # Reset overwriteOutput to what it was originally. arcpy.env.overwriteOutput = OverwriteOutput
def runTool(outStops, SQLDbase, day, start_time, end_time, DepOrArrChoice): try: BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2") BBB_SharedFunctions.ConnectToSQLDatabase(SQLDbase) Specific, day = BBB_SharedFunctions.CheckSpecificDate(day) start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds( start_time, end_time) # Will we calculate the max wait time? CalcWaitTime = True # ----- Create a feature class of stops and add fields for transit trip counts ------ try: arcpy.AddMessage("Creating feature class of GTFS stops...") # Create a feature class of transit stops outStops, StopIDList = BBB_SharedFunctions.MakeStopsFeatureClass( outStops) # Add a field to the output file for number of trips, num trips / hour, and max wait time if ".shp" in outStops: # Shapefiles can't have long field names arcpy.management.AddField(outStops, "NumTrips", "SHORT") arcpy.management.AddField(outStops, "TripsPerHr", "DOUBLE") arcpy.management.AddField(outStops, "MaxWaitTm", "SHORT") else: arcpy.management.AddField(outStops, "NumTrips", "SHORT") arcpy.management.AddField(outStops, "NumTripsPerHr", "DOUBLE") arcpy.management.AddField(outStops, "MaxWaitTime", "SHORT") except: arcpy.AddError("Error creating feature class of GTFS stops.") raise #----- Query the GTFS data to count the trips at each stop ----- try: arcpy.AddMessage( "Calculating the number of transit trips available during the time window..." ) # Get a dictionary of {stop_id: [[trip_id, stop_time]]} for our time window stoptimedict = BBB_SharedFunctions.CountTripsAtStops( day, start_sec, end_sec, BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice), Specific) except: arcpy.AddError( "Error counting arrivals or departures at stop during time window." ) raise # ----- Write to output ----- try: arcpy.AddMessage("Writing output data...") # Create an update cursor to add numtrips, trips/hr, and maxwaittime to stops if ".shp" in outStops: ucursor = arcpy.da.UpdateCursor( outStops, ["stop_id", "NumTrips", "TripsPerHr", "MaxWaitTm"]) else: ucursor = arcpy.da.UpdateCursor( outStops, ["stop_id", "NumTrips", "NumTripsPerHr", "MaxWaitTime"]) for row in ucursor: NumTrips, NumTripsPerHr, NumStopsInRange, MaxWaitTime = \ BBB_SharedFunctions.RetrieveStatsForSetOfStops( [row[0]], stoptimedict, CalcWaitTime, start_sec, end_sec) row[1] = NumTrips row[2] = NumTripsPerHr if ".shp" in outStops and MaxWaitTime == None: row[3] = -1 else: row[3] = MaxWaitTime ucursor.updateRow(row) except: arcpy.AddError("Error writing to output.") raise arcpy.AddMessage("Finished!") arcpy.AddMessage("Your output is located at " + outStops) except BBB_SharedFunctions.CustomError: arcpy.AddError("Failed to count trips at stops.") pass except: arcpy.AddError("Failed to count trips at stops.") raise