Select to view content in your preferred language

How to use attribute rules to get nearest neighbors distance?

1512
4
Jump to solution
08-18-2022 12:38 PM
Labels (3)
phess_luckstone
Regular Contributor

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;

  Screenshot 2022-08-18 153518.png

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Alum

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]}
}

 


Have a great day!
Johannes

View solution in original post

4 Replies
JohannesLindner
MVP Alum

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]}
}

 


Have a great day!
Johannes
phess_luckstone
Regular Contributor

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.

0 Kudos
JohannesLindner
MVP Alum

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.


Have a great day!
Johannes
0 Kudos
phess_luckstone
Regular Contributor

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;
0 Kudos