Best Practices for Attribute Rules

428
3
Jump to solution
01-06-2025 10:41 AM
Smileyk_mdt
Emerging Contributor

Hello,

I'm working on some validation attribute rules for data checks for our road log. I seem to get false positives on these checks often because I can't get the rules to filter to exclude retired routes. What are best practices when running attribute rule checks so that the retired routes (TO_DATE is Not NULL) don't show up in the results? I tried filtering using arcade but no success. It also doesn't seem to honor definition queries.

The error inspector window appears to be buggy at times. It doesn't refresh after I alter a rule. I'm running Pro 3.3

1 Solution

Accepted Solutions
James_Blouin
Emerging Contributor

Hey. Glad to help! Looking at your explanation and code, I can see a couple of things that might be causing the code to return an undesired result.

added an extra condition to exclude evaluation for Two Way Left Turn medians. 

If you are trying to exclude those values from evaluation, then you might want to change the code to use the != (inequality operator) instead of the == (equality operator) for your $feature.MEDIAN value check.

So change from this (equals)
$feature.MEDIAN == "Two Way Left Turn Lane"

To this (does not equal)
$feature.MEDIAN != "Two Way Left Turn Lane"

 

The other important (and often confusing) thing to consider is which "out-of-the-box" spatial relationship in Arcade should you choose to evaluate the geometry of your two features. Esri has a great resource to play around with geometry types and their spatial relationships here: Spatial relationships | Documentation | Esri Developer

If you're looking to find median line segments that do not exist on a divided-highway, then the overlaps function might not work for you. It seems that you might want to try "disjoint" instead.

Here's the section of the code updated to use the disjoint function:

 

 

 

 

// For each of the features returned in the Filtered feature set  
for (var c in cartoActive) {
  if (disjoint($feature, c)) { // If disjoint is true
    // Return the error message
    return {"errorMessage": `Median feature does not exist on a divided highway. Route ID: ${routeID}, Object ID: ${objectID}`}
  }
}

 

 

 

 

If disjoint doesn't work or you need a spatial relationship check that is more complex than the "out-of-the-box" functions, then you might want to explore the relate function.

This diagram is from MnDOT's RHUG presentation also illustrates the true/false result for various "out-of-the-box" spatial relationships in Arcade:

spatial_relationship_lines.jpg

We found that for most of our checks we needed a function that provided a combination of Overlaps, Within, and Contains (not pictured) and excluded cross-streets and adjacent lines that share a start or endpoint with our feature being evaluated. To accomplish this, we selected the "relate" function that allows us to define any spatial relationship we desire. This function utilizes the Dimensionally Extended 9-Intersection Model (DE-9IM) to define the spatial relationship. Here are a couple of links that dive into the details:
Custom spatial relationships—ArcGIS Pro | Documentation

26. Dimensionally Extended 9-Intersection Model — Introduction to PostGIS

And here's a snippet that gave us the "Desired result" shown in the diagram above:

 

 

 

 

for (var c in cartoActive) {
  if (relate($feature, c, '1********')) { // If true, return errorMessage
    return {"errorMessage": "Feature shares a line segment with cartoActive segment."}
  }
}

 

 

 

 

View solution in original post

3 Replies
James_Blouin
Emerging Contributor

Hi there! We at MnDOT are using an If-then statement at the beginning of our Validations where we want to exclude retired records or records that have null geometry. Here's an example:

 

// Only evaluate active features that have geometry
If ((geometry($feature) != null) && $feature.TO_DATE == null) {

 


For filtering Feature sets, we define a SQL query and use the Filter function:

 

var fs = FeatureSetByName($datastore, 'featureset')
var sql = "TO_DATE IS NULL"
var fsFilter = Filter(fs, sql)

 


And here's an example of code that we use to evaluate if a line segment from the filtered Feature Set overlaps the record being evaluated in the Validation

 

// Only evaluate $features that have geometry and are active (TO_DATE is null)
if ((geometry($feature) != null) && $feature.TO_DATE == null) {
  var routeID = $feature.ROUTE_ID
  var objectID = $feature.OBJECTID
  
  // Get 'Carto Feature' feature set
  var cartoFS = FeatureSetByName($datastore, 'Carto Feature')
  // Define the SQL query definition query to filter the feature set
  var sql = "ROUTE_ID = @routeID AND TO_DATE IS NULL"
  // Filter the feature set to only return active records where the Route ID is equal to the $feature being evaluated
  var cartoActive = Filter(cartoFS, sql)

  // For each of the features returned in the Filtered feature set  
  for (var c in cartoActive) {
    if (overlaps($feature, c)) { // If the $feature overlaps the feature from the feature set...
      // Return the error message
      return {"errorMessage": `Feature overlaps an activeCarto segment. Route ID: ${routeID}, Object ID: ${objectID}`}
    }
  }
}
return true

 



  

Smileyk_mdt
Emerging Contributor

Hello,

 

Thank you for those snippets as they are very helpful. We're new to these processes in MT. I saw your presentation for RHUG and it was also very helpful.

I'm working on a data check that will flag in red (validation attribute rule) any median that DOES NOT have a divided highway. I used the code above and added an extra condition to exclude evaluation for Two Way Left Turn medians. I'm getting weird behavior. It ignores TWLT as expected, but it still flags things that have a divided highway. Here is my code and a pic. In the pic, the 2 lonely lines at the top are correctly flagged because I removed their divided highways. The other two longer roads (that cross each other) have a divided hwy but still get flagged. I'm stumped on this one. I confirmed that the lines do overlap. Same ROUTE_ID, begin and end. They do have Z values if that matters

 

// Only evaluate $features that have geometry and are active (TO_DATE is null)
if ((geometry($feature) != null) && $feature.TO_DATE == null && $feature.MEDIAN == "Two Way Left Turn Lane") {
  var routeID = $feature.ROUTE_ID
  var objectID = $feature.OBJECTID
  
  // Get 'Carto Feature' feature set
  var cartoFS = FeatureSetByName($datastore, 'Divided_Highway_Export')
  // Define the SQL query definition query to filter the feature set
  var sql = "ROUTE_ID = @routeID AND TO_DATE IS NULL"
  // Filter the feature set to only return active records where the Route ID is equal to the $feature being evaluated
  var cartoActive = Filter(cartoFS, sql)

  // For each of the features returned in the Filtered feature set  
  for (var c in cartoActive) {
    if (overlaps($feature, c)) { // If the $feature overlaps the feature from the feature set...
      // Return the error message
      return {"errorMessage": `Feature overlaps an activeCarto segment. Route ID: ${routeID}, Object ID: ${objectID}`
    }
  }
}
return true
}

 

 

0 Kudos
James_Blouin
Emerging Contributor

Hey. Glad to help! Looking at your explanation and code, I can see a couple of things that might be causing the code to return an undesired result.

added an extra condition to exclude evaluation for Two Way Left Turn medians. 

If you are trying to exclude those values from evaluation, then you might want to change the code to use the != (inequality operator) instead of the == (equality operator) for your $feature.MEDIAN value check.

So change from this (equals)
$feature.MEDIAN == "Two Way Left Turn Lane"

To this (does not equal)
$feature.MEDIAN != "Two Way Left Turn Lane"

 

The other important (and often confusing) thing to consider is which "out-of-the-box" spatial relationship in Arcade should you choose to evaluate the geometry of your two features. Esri has a great resource to play around with geometry types and their spatial relationships here: Spatial relationships | Documentation | Esri Developer

If you're looking to find median line segments that do not exist on a divided-highway, then the overlaps function might not work for you. It seems that you might want to try "disjoint" instead.

Here's the section of the code updated to use the disjoint function:

 

 

 

 

// For each of the features returned in the Filtered feature set  
for (var c in cartoActive) {
  if (disjoint($feature, c)) { // If disjoint is true
    // Return the error message
    return {"errorMessage": `Median feature does not exist on a divided highway. Route ID: ${routeID}, Object ID: ${objectID}`}
  }
}

 

 

 

 

If disjoint doesn't work or you need a spatial relationship check that is more complex than the "out-of-the-box" functions, then you might want to explore the relate function.

This diagram is from MnDOT's RHUG presentation also illustrates the true/false result for various "out-of-the-box" spatial relationships in Arcade:

spatial_relationship_lines.jpg

We found that for most of our checks we needed a function that provided a combination of Overlaps, Within, and Contains (not pictured) and excluded cross-streets and adjacent lines that share a start or endpoint with our feature being evaluated. To accomplish this, we selected the "relate" function that allows us to define any spatial relationship we desire. This function utilizes the Dimensionally Extended 9-Intersection Model (DE-9IM) to define the spatial relationship. Here are a couple of links that dive into the details:
Custom spatial relationships—ArcGIS Pro | Documentation

26. Dimensionally Extended 9-Intersection Model — Introduction to PostGIS

And here's a snippet that gave us the "Desired result" shown in the diagram above:

 

 

 

 

for (var c in cartoActive) {
  if (relate($feature, c, '1********')) { // If true, return errorMessage
    return {"errorMessage": "Feature shares a line segment with cartoActive segment."}
  }
}