Map Viewer Styles with Arcade Expression: Working... but not actually

898
8
Jump to solution
11-03-2023 02:35 PM
Labels (2)
AaronKoelker
Occasional Contributor III

I have a hosted feature service of county boundaries within a web map: https://fgio.maps.arcgis.com/apps/mapviewer/index.html?webmap=c6d86a156e80458e8d4104d20c3900dc 

The feature service has several fields, each containing only Yes/No values. I want to stylize the layer by getting a count of how many instances of 'YES' there are across all attributes for each record. I wrote an Arcade expression within the Styles panel that correctly returns the number of instances as an integer. I also applied this expression to the pop-up, and can see the expected results for each feature when I click it. However, when I go to actually style the layer (Counts and Amounts (color) for example), the map won't draw using the results of the Arcade expression. It doesn't draw anything at all, or instead lumps everything into 'Other' if I toggle on that option. I have shared the map publicly so that the expression and setup can be viewed. 

I'm not sure if I'm running into an undocumented limitation or what. I have been scouring forums and have seen many examples that are powering a style with an integer returned by an expression, but I haven't been able to pinpoint why mine is failing. Any ideas? 

 

 

 

var fieldList = ['Dorian_2019','Sally_2020','Ian_2022','Nicole_2022','Idalia_2023']

var total = 0

for (var f in fieldList) {
    If ($feature[fieldList[f]] == 'YES') {
        total += 1
    }
}

return total

 

 

 

This spits out a simple integer. All of the results are between 0 and 4.

 

AaronKoelker_0-1699047299262.png

 

-Aaron
0 Kudos
1 Solution

Accepted Solutions
gis_KIWI4
Occasional Contributor

Hi @AaronKoelker 

I don't know the exact answer but my suspicion is that the arcade profile for symbology may not support the 'for' loop. I can see you expression does return a number and works perfectly in the pop-ups but struggles to use it when setting symbology. Maybe someone smarter than me can confirm that for us. 

I managed to get the symbology to work using a slightly tweaked arcade expression.
Hope that helps 🙂 

var total = 0
if ($feature.Dorian_2019 == "YES") {
  total = total + 1
}
if ($feature.Ian_2022=="YES") {
  total = total + 1
}
if ($feature.Idalia_2023=="YES") {
  total = total + 1
}
if ($feature.Nicole_2022=="YES") {
  total = total + 1
}
return total

 

gis_KIWI4_0-1699235054713.png

 

View solution in original post

8 Replies
gis_KIWI4
Occasional Contributor

Hi @AaronKoelker 

I don't know the exact answer but my suspicion is that the arcade profile for symbology may not support the 'for' loop. I can see you expression does return a number and works perfectly in the pop-ups but struggles to use it when setting symbology. Maybe someone smarter than me can confirm that for us. 

I managed to get the symbology to work using a slightly tweaked arcade expression.
Hope that helps 🙂 

var total = 0
if ($feature.Dorian_2019 == "YES") {
  total = total + 1
}
if ($feature.Ian_2022=="YES") {
  total = total + 1
}
if ($feature.Idalia_2023=="YES") {
  total = total + 1
}
if ($feature.Nicole_2022=="YES") {
  total = total + 1
}
return total

 

gis_KIWI4_0-1699235054713.png

 

AaronKoelker
Occasional Contributor III

Thanks! Your alternative works well. For any ESRI staff that may happen to come across this: if the FOR loop is indeed the issue, it would be nice to have that sort of stuff outlined in the Arcade/Map Viewer documentation, or perhaps a warning visible in the Styles or Arcade editor window when it notices a loop being used. Or if it exists somewhere I haven't found yet, I'd love to get a link. 

Appreciate your help!

-Aaron
0 Kudos
KenBuja
MVP Esteemed Contributor

It's probably not an issue with the for loop. Usually when you use a variable in retrieving feature attributes, you have to use the Expects function at the top of the script. This ensures that those attributes are getting requested properly.

Expect($feature, 'Dorian_2019','Sally_2020','Ian_2022','Nicole_2022','Idalia_2023');
var fieldList = ['Dorian_2019','Sally_2020','Ian_2022','Nicole_2022','Idalia_2023']
var total = 0

for (var f in fieldList) {
    If ($feature[fieldList[f]] == 'YES') {
        total += 1
    }
}

return total

 

AaronKoelker
Occasional Contributor III

Ah! Interesting. I did not know about the Expects function. Your solution works as well (I did have to add an 's' to 'Expect'). Appreciate the help!

-Aaron
0 Kudos
KristianEkenes
Esri Regular Contributor

@KenBuja  is correct. You should use the Expects function for this case if using a for loop.

The rendering engine for Online (JS API) is optimized for performance. So it only requests the data that's required by the layer's style by default. If you specify a field outside of an Arcade expression, the API knows to request data from that field for rendering. In the case of Arcade, the expression is evaluated for the fields required to make it work. When $feature.FIELDNAME is used, it's easy for the engine to figure out the required fields. That's why the alternative expression works. However, you can use Expects to directly tell the rendering engine which fields it should expect to request from the service. This can be a list of fields as Ken points out, or  you can also define template strings like the following:

Expects("*"); // requests all fields. Don't do this if you have a ton of attributes.

Expects("Year_*") // requests all fields that begin with "Year_". (e.g. "Year_2000", "Year_2010") would be requested, but "Y2004" wouldn't). 

On a side note, you could take advantage of the number function to condense the initial expression like this:

Expects($feature,'*_20*');
var fieldList = ['Dorian_2019','Sally_2020','Ian_2022','Nicole_2022','Idalia_2023'];
var total = 0;

for (var f in fieldList) {
  // adds 1 if "YES"
  // adds 0 if not "YES"
  total += Number($feature[fieldList[f]] == 'YES');
}
return total;

Or use the reduce function to avoid a for loop altogether. You still need Expects for this to work...

Expects($feature,'*_20*');
var fieldList = ['Dorian_2019','Sally_2020','Ian_2022','Nicole_2022','Idalia_2023'];

function add (total, fieldName){ total + Number($feature[fieldName] == 'YES') }
Reduce(fieldList, add, 0);

 

AaronKoelker
Occasional Contributor III

Thank you Kristian, that is all very useful as well! Would you expect a performance benefit using the Reduce function instead of a for loop on larger datasets? I tried both ways on my data, but didn't see a noticeable difference (perhaps became it is relatively small).

-Aaron
0 Kudos
KristianEkenes
Esri Regular Contributor

Not necessarily a performance benefit. Just an alternative that is fewer lines. I try to go with the shortest expression. Though I'd say the for loop version is more readable than the reduce approach.

0 Kudos
gis_KIWI4
Occasional Contributor

@KristianEkenes  @KenBuja - Thanks for the explanation. 
Learnt something new today - this goes straight into my list of resources 🙂 

0 Kudos