Find shortest route and export links that make up the route

808
5
04-28-2020 02:51 PM
FernandoCordero_Montoya1
New Contributor II

Hello. I am new at AcrPy and coding in general. I am working on the following task using ArcMap 10.7 Python Toolbox.

We are able to use the ArcPy code to generate a Network Dataset in ArcMap using Network Analyst functions. We want to find the shortest route between location A and location B listed in a feature class. 

What we'd like is: 

1- the shortest route (distance) from A to B, and

2 - the list of links that make up this route. Is this a property we can extract from the route?

In our code, we will be doing this thousand times, so we would like to avoid exporting thousands of routes if possible. Instead, we'd like to store the links in a large array.

We would greatly appreciate any suggestions or/and advice.

0 Kudos
5 Replies
JaySandhu
Esri Regular Contributor

After you solve a route analysis layer, you can run the GP tool Copy Traversed Source Features that creates a new feature class for the edges that made up the route. Also creates feature classes for the junctions and turns.

I did not understand your question on running a thousand times and NOT exporting it each time. What are your trying to do?

More info about the tool:

Copy Traversed Source Features—ArcGIS Pro | Documentation 

Jay Sandhu

FernandoCordero_Montoya1
New Contributor II

Hello Jay,

Thanks for your response.

We have over 1,000 zones that are connected with a network. We want to find and export the shortest route from A to B, A to C, A to D, A to n, etc. Then repeat from B to C, B to D, B to n. 

I was trying to find the route using Make Route Layer, however, the output feature class did not contain any values. I understand that the route details from "A" to "A" is zero (0) but there should be info for "A to B" and "A to C", "A to D"....etc. 

I found a similar discussion on Batch Solving Many Routes. Here you provided an alternative using the Closest Facility tool. I was wondering if this will apply to my scenario or there is a more suitable alternative.

Is it possible to run one pair (said A to B) at a time, export route using Copy Traversed Source Features, store and continue to next pair (said A to C), etc?

Thank you in advance.

0 Kudos
JaySandhu
Esri Regular Contributor

The best way is to use the Closest Facility solver. You make the CF layer. Then load your 1000 locations as Facilities and also as Incidents. Set the property to solve all 1000 routes. And solve. it will solve the 1000 by 1000 routes, i.e. a million routes and the shortest path and cost will be in the routes sub layer. If you need the individual links that make up each route, you can run the Copy Traversed Source Features.

I suggest that you try on a 10 by 10 case to make sure you have the process correct before trying it on all 1000.

As for your other issue:

>I was trying to find the route using Make Route Layer, however, the output feature class did not contain any values. I understand that the route details from "A" to "A" is zero (0) but there should be info for "A to B" and "A to C", "A to D"....etc. 

I do not follow. What stops did you load into the route layer? Two stops A and B? After solve, did you not see an output route displayed on the map? Or if you open the attribute table for the routes sub layer, do you not see any row for the route you solved? If you cannot get ANY route to solve then perhaps the network is not set up correctly. 

Jay Sandhu

0 Kudos
FernandoCordero_Montoya1
New Contributor II

Hi Jay,

Thanks for your response. I will do as you recommended.

Following up on your last question. I will show you my script.

#7 Make Route Analysis

import arcpy
from arcpy import env
import datetime
import os




#Set enviroment settings

output_dir = os.path.dirname(NDTemplate)

#The NA layer's data will be saved to the workspace specified here

env.workspace = os.path.join(output_dir, "BikeTool.gdb")
env.overwriteOutput = True

# Local Variables

input_gdb = os.path.join(output_dir, "BikeTool.gdb")
inNetworkDataset = os.path.join(output_dir, "BikeTool_Data2/BikeTool.gdb" , "BikeTool_Network_ND")
stops_home = os.path.join(output_dir, "BikeTool_Data2/BikeTool.gdb" , "Blocks_CentroidOrigin")
stops_work = os.path.join(output_dir, "BikeTool_Data2/BikeTool.gdb", "Blocks_CentroidDestination")
outNALayerName = "BikeNetwork"
out_routes_featureclass = os.path.join(output_dir,"BikeTool_Data2/BikeTool.gdb","RoutesFC")
travel_mode = "Driving Time"
impedance_Attribute = "Length"

#Set the time of day for the analysis to 8AM on a generic Monday.

import datetime

start_time = datetime.datetime(1900, 1, 1, 8, 0, 0)

#Create a new Route layer. Optimize on driving time, but compute the distance traveled by accumulating the Meters attribute.

import arcpy

result_object = arcpy.na.MakeRouteLayer (inNetworkDataset, outNALayerName,
                                                                     impedance_Attribute,
                                                                     accumulate_attribute_name=["Length"],
                                                                     hierarchy="NO_HIERARCHY",
                                                                     start_date_time=start_time)

#Get the layer object from the result object. The route layer can now be referenced using the layer object.

layer_object = result_object.getOutput(0)

#Get the names of all the sublayers within the route layer.


naclass_edit_type = "ANY"
nalocation_type = "ANY"
shape_type = "ANY"


subLayerNames = arcpy.na.GetNAClassNames(layer_object,
                                                                              naclass_edit_type,
                                                                              nalocation_type,
                                                                              shape_type)

#Stores the layer names that we will use later


stops_layer_name = subLayerNames["Stops"]
routes_layer_name = subLayerNames["Routes"]

#Before loading the commuters' home and work locations as route stops, set up field mapping. Map the "ORIG_FID" field from the input data to
#the RouteName property in the Stops sublayer, which ensures that each unique ORIG_FID will be placed in a separate route. Matching
#Commuter_Names from stops_home and stops_work will end up in the same route.

field_mappings = arcpy.na.NAClassFieldMappings(layer_object, stops_layer_name)
field_mappings["RouteName"].mappedFieldName = "ORIG_FID"

#Add the commuters' home and work locations as Stops. The same field mapping works for both input feature classes because they both have a field called
#"ORIG_FID"

arcpy.na.AddLocations(layer_object, stops_layer_name, stops_home,
                                       field_mappings, "",
                                       exclude_restricted_elements = "EXCLUDE")
arcpy.na.AddLocations(layer_object, stops_layer_name, stops_work,
                                       field_mappings, "",
                                       exclude_restricted_elements = "EXCLUDE")

#Solve the route layer.


arcpy.na.Solve(layer_object)

#Get the output Routes sublayer and save it to a feature class


routes_sublayer = arcpy.mapping.ListLayers(layer_object,routes_layer_name)[0]
arcpy.management.CopyFeatures(routes_sublayer, out_routes_featureclass)

>>>>>>

I was running this script hoping to obtain the routes, the attribute table of the output feature class did list the routes but only solved for A to A, B to B, C to C. Therefore there is no route displayed on the map nor the length of that route.

I follow Make Route Layer—Help | Documentation. I used the same feature class for my "home" stops and "work" stops. I only change the name of the file. Also, I know the network is working fine because I can use the route analysis tool and manually choose any origin and destination, solve, and obtain a route with all the information.

Thank you in advance.

0 Kudos
JaySandhu
Esri Regular Contributor

In your script you are loading stops_home and stops_work which point to Blocks_CentroidOrigin and Blocks_CentroidDestination.  What do these two feature classes contain? Do they contain the same set of 1000 locations? If yes, then you are mapping A to A, B to B, C to C, etc., based on the routename property and thus getting only those pairs of paths. What you need to do is load A, 1000 times with routename 1 and then load A to A1000 locations with the same routename. That is how Route works. So if you cannot load in this way then use Closest Facility as it will solve 1 to many.

Jay Sandhu