Select to view content in your preferred language

Help with Custom Evaluators in ArcGIS Pro 3.2

564
2
12-19-2023 11:26 AM
Gideon_Singer_Abt
Emerging Contributor

Hello, I need some help understanding how best to use Custom evaluators—ArcGIS Pro | Documentation with ArcGIS Pro 3.2. I am attempting to create a custom evaluator class that will mimic the behavior of adding a strong restriction or preference for routes based on an attribute value. However, I have a list of many different attribute values I need to create routes for to demonstrate how the route solver output changes. 

I think my trouble is that this class might only be accessing the cost attribute of the Edge and not actually looking at when Edge != Priority_Type.

 

Anybody have advice? 

 

class EdgeCustomizer(arcpy.nax.AttributeEvaluator, Priority_Type):
    def attach(self, network_query: arcpy.nax.NetworkQuery) -> bool:
        """Connect to and validate the network dataset."""
        # Do additional validation checks before returning Boolean
        return True

    def refresh(self) -> None:
        """Reset internal state before solve."""
        # Reset internal state in this method as needed
        pass
    
    def edgeValue(self, edge: arcpy.nax.Edge, Priority_Type):
        # Get the value of the "Field_Type" attribute for the current edge
        field_type_value = self.networkQuery.attributeValue(edge, "Field_Type")
        # Check if the value is not equal to Priority_Type
        if field_type_value != Priority_Type:
            base_value = self.networkQuery.attributeValue(edge, self.attribute)
            base_multiplier = 10
            return base_value * base_multiplier
        else:
            # Return the original cost if the value is Priority_Type
            return self.networkQuery.attributeValue(edge, self.attribute)

 

0 Kudos
2 Replies
Gideon_Singer_Abt
Emerging Contributor

Also, what had me interested was the following quote: "Custom evaluators are implemented by creating a Python class that inherits from the arcpy.nax.AttributeEvaluator and associating the Python class with a particular network dataset. They can be associated with cost, restriction, or descriptor attributes. They can update edges, junctions, or turns for time-enabled solves as well as solves that are not time enabled. Depending on the changes made, the updates may alter the costs and paths found during analysis". 

I am hoping to create a temporary cost/restriction that will be used to update edges during a route solve. 

0 Kudos
FrankKish
Esri Contributor

Custom evaluators work on network elements (e.g. edges), as such source feature field values are not directly accessible, but a network descriptor attribute that accesses source feature field values can be used instead.

In your case it looks like you have an attribute called Field_Type that you want to use in the custom evaluator. And I think you want to be able to pass in a value to use as the priority type.

Step 1 - Update the network dataset
- open the network dataset properties
- go to Travel Attribute > Descriptors
- add a descriptor attribute that reads the Field_Type attribute (e.g. naming it Field_Type_Descriptor)
- re-build the network

Step 2 - Update the custom evaluator code

a) Add the init method with an argument for the priority type value

def __init__(self, attribute_name: str, Priority_Type: int): 
self.priority_type = Priority_Type
super().__init__(attribute_name)

b) In the refresh method get the descriptor’s attribute index:

def refresh(self) -> None: 
self.field_type_descriptor = self.networkQuery.attribute("Field_Type_Descriptor")

c) In edgeValue use descriptor attribute index to get the field value:

def edgeValue(self, edge: arcpy.nax.Edge) : 
base_value = self.networkQuery.attributeValue(edge, self.attribute)
field_type_value = self.networkQuery.attributeValue(edge, self.field_type_descriptor)
if field_type_value != self.priority_type:
base_multiplier = 10
return base_value * base_multiplier
else:
return base_value


Setup 3 - update the solving code

When creating an EdgeCustomizer object pass in the cost attribute name that will be update and the value of the priority to use.

priority_value = 5
# set the cost attribute to alter and the priority value to use
ce_list = [EdgeCustomizer("TravelTime", priority_value)]
network_dataset.customEvaluators = ce_list


I've also attached an example script with the above and gdb where I added a Field_Type to the streets and a descriptor to the network dataset (the data is a small subset of the San Fransisco data in the Network Analyst Pro Tutorial data).

Tell me if this helps.

 

 

0 Kudos