Previously, I was working in ArcMap 10.6.1 and created a script utilizing the arcpy.na module. I had no Python background prior to this rather large undertaking, so my (still limited) Python knowledge is based in ArcGIS.
The purpose of this script was to iterate through a set of polygons, select the intersecting points in each polygon, load these points into a new Network Analysis Route layer, solve that route, then move on to the next polygon and repeat.
It was working pretty well! Then, I decided to migrate to Pro 2.5...
I was successful in most of my gp tool migrations. However, there are 2 major "module-based" issues I am having:
1. I am having difficulty understanding how to migrate from the arcpy.mapping module to the arcpy.mp module in Pro.
2. I've been a little confused with the differences between the .nax module and the legacy .na module, even after reading the "choose your module" help page. The .nax module seems much simpler and more straightforward, but it appears to not have the ability to create network analysis layers. That is the main function of my script.
I feel as though I am back at square one trying to navigate these migrations. Does anyone have any experience moving to these new modules? Is anyone else in the same boat as me?
Hi Jordan.
If you want to keep your script mostly the same and continue to use NA layers, that will work. But, as you have discovered, there are some code changes required, particularly with regards to working with the arcpy.mapping module in Pro.
This page has some tips about how to migrate an NA layer-based workflow to Pro: Migrating arcpy.na to ArcGIS Pro—Network Analyst module | Documentation
And this page talks about migrating to Pro for the arcpy.mapping module: Migrating from arcpy.mapping to ArcGIS Pro—ArcPy | Documentation
Regarding the newer arcpy.nax module: Yes, the workflows are more straightforward, and as you have noticed, they are not based on layers at all. There is the ability to export an NA layer after solving the analysis, but the primary intent there is for debugging problems. The primary assumption is that at the end of the day, most people just need the Service Area polygons or maybe just a couple of field values from the output of the analysis. The arcpy.nax module allows you to access those things directly. You can use the export() method to export the polygons to a feature class on disk, or you can loop through the analysis results using a search cursor if you just need to grab a few field values.
Does this help?
If you are having trouble with a few specific lines of code, feel free to paste them here and I can take a look.
Hey Melinda,
Thank you for your quick response. I read through the materials again with your explanations in mind and I attempted to edit my script accordingly. I was going to give it a whirl again using the .nax module and foregoing the arcpy.mp module (since the .nax module is more straightforward with exporting fields).
However, I had a .nax module issue from the get-go. Even after checking out the network analyst extension, I am receiving this error on the following line:
route.load(arcpy.nax.RouteInputDatatype.Stops, input_stops)AttributeError: module 'arcpy.nax' has no attribute 'RouteInputDatatype'
Is this a sign that I should instead try to utilize the arcpy.mp module in conjunction with the legacy arcpy.na module?
Don't give up yet! You just have a capitalization error, and the code is case sensitive. It's "Type", not "type" in "RouteInputDataType".
Thank you Melinda! That's all I needed to make it work, and it looks great!
The .nax module is definitely more straightforward and user-friendly; it looks like I saved myself about 20 lines of code with the switch.
I do have one (hopefully) last question, regarding the returnDirections property. I have read that .nax stores everything in memory, and I would like to view the turn-by-turn directions for the generated route. I do not have much experience with in-memory storage. Is there a quick line of code I can insert to call to the route directions output, using that returnDirections property on the route solver?
My purpose in viewing the directions is to see the sequence of the stops that are used on the route. Is there a better way to view the sequence using the .nax module than trying to view the directions output?
Yes, that's definitely possible. What you want is the Sequence field in the output Stops.
This page lists the field available in the outputs: Route output data types—ArcGIS Pro | Documentation
One way to access that field is to use the export() method to save the output Stops to a feature class and then use it the same way you would any feature class. But if you just want to get the sequence values, you can use searchCursor() to access them directly:
result = route.solve()
fields = ['Name', 'RouteName', 'Sequence']
for row in result.searchCursor(arcpy.nax.RouteOutputDataType.Stops, fields):
print(row)
Here is the documentation for searchCursor: SolverResultSearchCursor—ArcGIS Pro | Documentation
Hello Melinda,
Thanks again for all the help lately! That method worked perfectly and I feel confident with the .nax module for routing now!
Down the line we are possibly going to be using this script to host map services, so I am also trying to fix the .na module code to work in Pro and to better my understanding of its differences. Now I am having difficulty with the MakeRouteAnalysisLayer method.
On this line:
layer_object = arcpy.na.MakeRouteAnalysisLayer(network, route_name, "Driving Time", "FIND_BEST_ORDER", "", "", "ALONG_NETWORK", "", "DIRECTIONS", "")
I am receiving this error:
TypeError: MakeRouteAnalysisLayer() takes from 0 to 9 positional arguments but 10 were given
I am working from this syntax:
MakeRouteAnalysisLayer(network_data_source, {layer_name}, {travel_mode}, {sequence}, {time_of_day}, {time_zone}, {line_shape}, {accumulate_attributes}, {generate_directions_on_solve}, {time_zone_for_time_fields})
Previously, when I attempted to modify my code for use in Pro (before my initial post requesting help), it was not returning this error. Any insight into this?
Thanks in advance,
Jordan
The time_zone_for_time_fields parameter was just added at ArcGIS Pro 2.6, so if you have not updated to 2.6 yet, that's probably the source of the error. You can just leave out the last "" in your call to MakeRouteAnalysisLayer.
Ah, ok that makes sense. I didn't see an option to view syntax specifically for 2.5; is that documented somewhere or is it more of an understanding gained from working in Pro more and more?
That worked for me, but I am now getting an error when I try to load my points into the stops sublayer. I am wondering if it is a similar issue, where one of the parameters I am using is only for 2.6?
This is the block of code I am using:
layer_object = arcpy.na.MakeRouteAnalysisLayer(network,route_name,"Driving Time","FIND_BEST_ORDER","","","ALONG_NETWORK","","DIRECTIONS").getOutput(0)
sublayer_names = arcpy.na.GetNAClassNames(layer_object)
stops_sublayer_name = sublayer_names["Stops"]
routes_sublayer_name = sublayer_names["Routes"]
arcpy.na.AddLocations(layer_object, stops_sublayer_name, input_points, "", "5000 Meters", "IDNO", "", "MATCH_TO_CLOSEST", "APPEND", "NO_SNAP", "5 Meters", "INCLUDE", "")
arcpy.na.Solve(layer_object, "SKIP")
This is the error returned on line 7:
ExecuteError: Failed to execute. Parameters are not valid.
ERROR 000840: The value is not a Network Analyst Layer.
Failed to execute (AddLocations).
I am confused as to why it is not recognizing my "layer_object" as an NA Layer, especially because I can see the NA Layers being added to my map and table of contents while the script is running.
Also, I apologize for asking so many questions! I am usually pretty good about being able to research my errors and figure out a solution, but I feel like with all the updates to Pro and new modules I need to utilize, I'm having difficulty finding common errors and solution documentation.
Thank you in advance!
Yeah the ArcMap doc had a little selector box on each page that let you view the page for previous software release versions, but I don't see that in Pro. I'm not sure why.
Your code looks fine, so I don't know why it's not working. You could try route_name instead of layer_object in the AddLocations input. That should also work.