Network Analyst and Script Evaluators: accessing attributes, get "network element evaluator error"

3460
26
05-06-2018 12:00 PM
BradSrebnik
New Contributor III

I'm trying to create a route using Network Analyst.  Just at the beginning stages of setting this up for a school project.

I have a feature class called RoadsClipped, and successfully set up a Network Dataset called Roads_ND using it.

Now I'm trying to customize the routing cost using evaluators.  I want to use attributes in RoadsClipped, but anything I've tried to access those attributes results in a "Network element evaluator error".  I've tried both VBScript and Python.

Some simple examples are below.  I've tried literally hundreds of variations and nothing work unless I forego trying to look at the attribute entirely.  These are just simple tests to see if I can get at the attributes in RoadsClipped, and not the real logic I'll eventually use.

Python:

def SetCost(value):
    a=Edge.AttributeValueByName(value)
    c=0
    if l!=0:
        c=100/a
    return c

value=SetCost("SPEED_LIM")

VBScript:

a=0
a=Edge.AttributeValueByName("SPEED_LIM")

value = a

Any suggestions?

0 Kudos
26 Replies
BradSrebnik
New Contributor III

I did not rebuild the network and I don't think you need to.  As I noted above, when I changed the call to "Value = SetCost(0)" it does not produce an error (and every other working, but useless simple test works without rebuilding).

0 Kudos
MelindaMorang
Esri Regular Contributor

I can't explain why your simple test with Value=SetCost(0) worked.  However, speaking as an member of the Network Analyst development team, I can vouch for the fact that you DO need to rebuild your network when you make any changes to the attributes and their evaluators.  Otherwise the changes will not get properly baked into the network, so at that point all bets are off.

To re-build your network, find it in the Catalog pane, right-click it, and choose Build.  Alternatively, use the Build Network geoprocessing tool.

Please try this and see if it fixes the problem.

0 Kudos
BradSrebnik
New Contributor III

Thanks again... Some updates.

First I changed to using Field not Script evaluators as you suggested.  With Field evaluators, I can see SPEED_LIM in the list of fields and use it in the script, so that is very good!  I don't recall seeing any example of field evaluator scripts in the ESRI help so I thought they were only simple things like constants.

With field evaluators, it does appear that you need to re-build, as you say.  That didn't seem to be the case with script evaluators.

I still have no idea what the difference between field and script evaluators is, other than that field evaluators give you access to the fields successfully.  The ESRI help has examples with script evaluators doing something like that, but it doesn't seem to work.

0 Kudos
BradSrebnik
New Contributor III

One step forward, on backwards 

I now have (again, to test that I can access the fields) this code:

def SetCost():
    lim=!SPEED_LIM!
    cost=10000
    if lim is not null:
        cost=lim
    return cost

Value = SetCost()

Verify says the syntax is OK.  As you suggest, I re-Build the dataset.  It says there is an error with every object:

SourceName: RoadsClipped, ObjectID: 1, Network object evaluator error.
SourceName: RoadsClipped, ObjectID: 2, Network object evaluator error.
...

0 Kudos
MelindaMorang
Esri Regular Contributor

Now you're on the right track. Try something more like this:

def SetCost(lim):
    cost=10000
    if lim is not null:
        cost=lim
    return cost
 
Value = SetCost(!SPEED_LIM!)

In the Value= box, you have to pass in the field value.  Then, in the function, it retrieves the value as an argument.  As it was, you were passing nothing to the function, and the function was trying to get the value from the field, but it doesn't know how to do that.

With all that said, the logic here doesn't make sense to me.  You're saying that the cost should be 10,000, unless the input field has a non-null value, in which case the cost should equal the speed limit.  Shouldn't the cost be a function of the speed limit and the length of the street (assuming you're calculating time)?

Maybe at this point you should tell me what your goal is.  What are you really trying to calculate?  Then perhaps I can better advise on the best way to achieve this.

0 Kudos
MelindaMorang
Esri Regular Contributor

Field evaluators allow you to read from the fields in the source feature classes and do simple script-related operations with them.  When you build the network, the values are read from the data and any associated script is run, and the values themselves are baked into the network at that time.

Script evaluators are meant for doing more complex and customized calculations that require access to multiple other network attributes and their parameters, network edge and junction properties, and other fancy things.  The scripts here are evaluated at solve time rather than during the network build, so they are much slower.  Rather than just looking up a stored value, they have to actually evaluate the script.

Since, during the previous discussion, you were still using a script evaluator, that explains why changing the value to 0 did not require a re-build.  However, it also explains why my suggestions did not work for you, since they were based on the assumption that you were now using a field evaluator.

Don't worry.  This stuff is confusing, and you're right that the documentation does not always provide good examples.

0 Kudos
BradSrebnik
New Contributor III

For background, we are hoping to use more than one field to set the cost.  The examples I've given do not necessarily make sense - they are only to test that I can access the field and do SOME sort of calculation.  If I am limited to only getting access to one field that may be a problem.

0 Kudos
MelindaMorang
Esri Regular Contributor

You can use more than one field in a field evaluator.  You can pass in multiple fields to your function.  Here's a made-up example:

def SetCost(lim, dist):
    cost=10000
    if lim is not null:
        cost=lim/dist
    return cost
 
Value = SetCost(!SPEED_LIM!, !DISTANCE!)
0 Kudos
BradSrebnik
New Contributor III

Excellent!  Thank you!  I will work with this and let you know how it goes...

0 Kudos
BradSrebnik
New Contributor III

This still does not work.  Even simplifying to the following gives a network object evaluator error for every object when I re-Build:

def SetCost(lim):
    cost=10000
    if lim is not null:
        cost=lim*lim
    return cost

Value = SetCost(!SPEED_LIM!)

0 Kudos