Select to view content in your preferred language

Arcade expressions for symbology

2889
5
Jump to solution
04-21-2021 06:01 PM
Labels (1)
BHeist
by
Occasional Contributor

I have a feature layer that can have multiple points at a single location. I was wondering if there was a way to use an Arcade expression to evaluate which point has the most recent date and then symbolize only that point? 

 

I know you can't use Filter() and OrderBy() with symbology so wasn't sure if it could be done any other way?

 

thanks! 

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

It looks like you can't do this directly in the symbology settings.

You'd need the $datastore or $map global to do an Intersect, and they are not available in the Visualization profile.

I'd create a new field and an Attribute Rule:

 

// field: ShowFeature, numeric
// triggers: insert (not update!)

// This rule checks whether a new feature is at the same location as other
// features in the same feature class. If so, it edits the field ShowFeature
// for those other features to be 0. For the feature itself, that field will
// be set to 1.
// In your map, you can then hide the features where ShowFeature = 0, either
// via a definition query or via the symbology settings. This way, if there
// are multiple feature in the same location, only the most recently added
// feature is shown.

// Get a reference to the feature class the new feature belongs to.
var fs = FeatureSetByName($datastore, "database.owner.class", ["GlobalID"], true)
// Intersect the new feture with the whole feature class.
// Here "features in the same location" means "at that exact point".
// If you want to check for "features at a certain distance around the new 
// feature", you should do this instead:
// var inter = Intersects(fs, Buffer($feature, 10, "meters"))
var inter = Intersects(fs, $feature)

// You will find at least 1 intersecting feature (the new feature itself).
// If there is exactly 1 intersecting feature, that means that there are no
// other features in the same location. Just return ShowFeature = 1.
if(Count(inter) == 1) {
  return 1
}

// If you get here, there are multiple features in the same location.
// For the older features (the ones that aren't $feature), you want to
// set ShowFeature = 0.
var updates = []

for(var fi in inter) {
  // Check if the currently tested feature (fi) ist the newly added one
  // ($feature). We do that here by comparing GlobalIDs.
  if(fi["GlobalID"] != $feature["GlobalID"]) {
    // If fi is not the new feature, we want to hide it
    updates[Count(updates)] = {"globalID": fi["GlobalID"], "attributes": {"ShowFeature": 0}}
  }
}

// Now we return the result.
// We set $feature.ShowFeature to 1 ("result": 1).
// And we edit all intersecting features in the same feature class
// with the update array we filled above.
return {
  "result": 1,
  "edit": [{
    "className": "owner.class",
    "updates": updates
  }]
}

 

Then, you can hide the features where ShowFeature = 0, either with a query or in the symbology.


Have a great day!
Johannes

View solution in original post

5 Replies
JohannesLindner
MVP Frequent Contributor

It looks like you can't do this directly in the symbology settings.

You'd need the $datastore or $map global to do an Intersect, and they are not available in the Visualization profile.

I'd create a new field and an Attribute Rule:

 

// field: ShowFeature, numeric
// triggers: insert (not update!)

// This rule checks whether a new feature is at the same location as other
// features in the same feature class. If so, it edits the field ShowFeature
// for those other features to be 0. For the feature itself, that field will
// be set to 1.
// In your map, you can then hide the features where ShowFeature = 0, either
// via a definition query or via the symbology settings. This way, if there
// are multiple feature in the same location, only the most recently added
// feature is shown.

// Get a reference to the feature class the new feature belongs to.
var fs = FeatureSetByName($datastore, "database.owner.class", ["GlobalID"], true)
// Intersect the new feture with the whole feature class.
// Here "features in the same location" means "at that exact point".
// If you want to check for "features at a certain distance around the new 
// feature", you should do this instead:
// var inter = Intersects(fs, Buffer($feature, 10, "meters"))
var inter = Intersects(fs, $feature)

// You will find at least 1 intersecting feature (the new feature itself).
// If there is exactly 1 intersecting feature, that means that there are no
// other features in the same location. Just return ShowFeature = 1.
if(Count(inter) == 1) {
  return 1
}

// If you get here, there are multiple features in the same location.
// For the older features (the ones that aren't $feature), you want to
// set ShowFeature = 0.
var updates = []

for(var fi in inter) {
  // Check if the currently tested feature (fi) ist the newly added one
  // ($feature). We do that here by comparing GlobalIDs.
  if(fi["GlobalID"] != $feature["GlobalID"]) {
    // If fi is not the new feature, we want to hide it
    updates[Count(updates)] = {"globalID": fi["GlobalID"], "attributes": {"ShowFeature": 0}}
  }
}

// Now we return the result.
// We set $feature.ShowFeature to 1 ("result": 1).
// And we edit all intersecting features in the same feature class
// with the update array we filled above.
return {
  "result": 1,
  "edit": [{
    "className": "owner.class",
    "updates": updates
  }]
}

 

Then, you can hide the features where ShowFeature = 0, either with a query or in the symbology.


Have a great day!
Johannes
BHeist
by
Occasional Contributor

Johannes,

Just so I can be sure I'm understanding your logic here...

You're creating a FeatureSet, new feature ($feature) is always the most current one, to run an 'Intersect' against the same layer to identify which locations have multiple points. For these locations you're testing the Global IDs against each other to identify which ones match the newly created FeatureSet(being the most recent). The ones that match get a '1' and the ones that don't get a '0'. Then you can use that field to hide the '0's and display the '1's. This way only the most recent records are being displayed in locations where there are multiple records?

 

Am I understanding that correctly?

0 Kudos
JohannesLindner
MVP Frequent Contributor

Pretty much, yeah. I added a whole bunch of comments in the original code, hopefully that makes it clearer.


Have a great day!
Johannes
BHeist
by
Occasional Contributor

It does! Just wanted to repeat in my own words too, to make sure I was understanding it. 

This is great, thank you so much!!

I'll get it implemented and mark it as a solution once I'm able to verify it works for me.

 

Thanks again for all your help. 

0 Kudos
SamanthaAPCC
Emerging Contributor

Hello @BHeist or @JohannesLindner .  I am trying to follow this same method for a hosted feature layer that I have.  If I'm understanding this correctly, I have to create an Attribute Rule in ArcGIS Pro and then share that layer to AGOL?  Does the attribute rule transfer?  Or is there somewhere in my online map where I can use this arcade language?

 

Thanks!

0 Kudos