I am trying to use attribute rules to write in the distance to a nearest neighbor, I've been able to get the nearest neighbors name to show up, however the distance alludes me. Here is the code I was using, however when add an area it seems to pick up the 3rd closest neighbor and not the nearest, can anyone help me figure out what I am doing wrong.
var NeighborLayer = FeatureSetByName($datastore, "TestNeighbors", ["NAME"]);
var searchDistance = 10000;
var NeighborIntersect = Intersects(NeighborLayer, Buffer($feature, searchDistance, "feet"));
var cnt = Count(NeighborIntersect);
var minDistance = 10000;
var name = Null
if (cnt > 0) {
for (var Neighbor in NeighborIntersect) {
var dist = Distance(Neighbor, $feature, "feet");
}
} else {
// pass no features found within search distance, name remains null
}
return dist;
Solved! Go to Solution.
After line 10, you have to check is dist < minDistance. If yes, update minDistance and name. At the end, return minDistance.
Easier way:
// Attribute Rule
// field: empty!
var NeighborLayer = FeatureSetByName($datastore, "TestNeighbors", ["NAME"]);
var searchDistance = 10000;
var NeighborIntersect = Intersects(NeighborLayer, Buffer($feature, searchDistance, "feet"));
// return early if nothing nearby, this saves you from all the indentation
if(First(NeighborIntersect) == null) {
return
}
// create an array of dictionaries
var neighbor_attributes = []
for(var neighbor in NeighborIntersect) {
var dist = Distance(neighbor, $feature, "feet")
var att = {"NearestNeighbor": neighbor.Name, "Distance": dist}
Push(neighbor_attributes, att)
}
// sort the array by distance
function sort_by_distance(a, b) {
return a["Distance"] - b["Distance"]
}
neighbor_attributes = Sort(neighbor_attributes, sort_by_distance)
// return the nearest neighbor's name and distance in one go
return {
"result": {"attributes": neighbor_attributes[0]}
}
After line 10, you have to check is dist < minDistance. If yes, update minDistance and name. At the end, return minDistance.
Easier way:
// Attribute Rule
// field: empty!
var NeighborLayer = FeatureSetByName($datastore, "TestNeighbors", ["NAME"]);
var searchDistance = 10000;
var NeighborIntersect = Intersects(NeighborLayer, Buffer($feature, searchDistance, "feet"));
// return early if nothing nearby, this saves you from all the indentation
if(First(NeighborIntersect) == null) {
return
}
// create an array of dictionaries
var neighbor_attributes = []
for(var neighbor in NeighborIntersect) {
var dist = Distance(neighbor, $feature, "feet")
var att = {"NearestNeighbor": neighbor.Name, "Distance": dist}
Push(neighbor_attributes, att)
}
// sort the array by distance
function sort_by_distance(a, b) {
return a["Distance"] - b["Distance"]
}
neighbor_attributes = Sort(neighbor_attributes, sort_by_distance)
// return the nearest neighbor's name and distance in one go
return {
"result": {"attributes": neighbor_attributes[0]}
}
This is awesome and it works on the database side when I bring in those layers directly into Pro from our SDE. However when I tried to use that with a published service it didn't work, any ideas why, is it because it updates both fields at once? When I tried to publish with this attribute rule turned on it wouldn't even let me publish but after deleting the attribute rule it let me.
You probably have to publish the TestNeighbors in the same service, too.
If this doesn't work, then I don't know, the whole service thing is very trial-and-error for me.
You could try doing both fields in their own rule. Just select the field and change the return to
return neighbor_attributes[0]["NearestNeighbor"] and
return neighbor_attributes[0]["Distance"]
respectively.
Thank you for your reply, I believe that services can't handle array's and using what you had mentioned earlier this code works in our service perfectly, thank you for your help!
var NeighborLayer = FeatureSetByName($datastore, "Neighbors Feature Class", ["NAME"]);
var searchDistance = 10000;
var NeighborIntersect = Intersects(NeighborLayer, Buffer($feature, searchDistance, "feet"));
var cnt = Count(NeighborIntersect);
var minDistance = Infinity;
var name = Null
if (cnt > 0) {
for (NeighborLayer in NeighborIntersect) {
var dist = Distance(NeighborLayer, $feature, "feet");
if (dist < minDistance) {
minDistance = dist
}
}
} else {
// pass no features found within search distance, name remains null
}
return minDistance;