Arcade Data Expression - Return Predominant Value while Grouping By Another Field

962
3
03-22-2022 04:38 PM
cwlee27
New Contributor II

Hello,

I am working on a data expression in Dashboards (ArcGIS Online) that returns the Count of features by Location.  I have that part figured out, but I'd like to also return the predominant value from another field ('categories').  How would I go about doing that.?  Below is my expression that returns the features grouped by location.

Ideally, I want a List that shows: "Country, Total Incidents, Predominant Incident Categories is ___."

Any advice is much appreciated, thanks!

 

// return fs that is grouped by 'Location' and gets 'COUNT' of features for that location
var fs = FeatureSetByPortalItem(Portal('https://myorg.maps.arcgis.com/'), 'myItemID', 0, ['Location'], false);

return GroupBy(fs, ['Location'],
[{name: 'total_incidents', expression: 'Location', statistic: 'COUNT' }
]);

 

0 Kudos
3 Replies
KimGarbade
Occasional Contributor III

I hope I understand what you mean by "Predominant Incident". 

I defined it to mean if you had 10 car crashes (for example 5 Multi Car, 3 Single Car, 1 Bicycle, 1 Pedestrian) the predominant type would be "Multi Car"

Another thing I will say is that I'm testing this on my home ArcGIS Pro single use install, so I didn't write the Arcade for a dashboard pulling from a portal, but the logic should be pretty similar.

I had test data laying around so I used  that and wrote an attribute rule to populate a new field named "Predominent" (spelled wrong) with the predominant value from the TextTst field (in the image below I updated the IntTest field from 6 to 7 to fire the Arcade to populate the Predominent field)

KimGarbade_0-1648032869813.png

The expression I used uses OrderBy (DESCending) to order the feature set returned by the GroupBy function in descending order from most to least occurrences of COUNT.  The First function just takes the first record from this ordered feature set. 

The only problem is if you have a tie its only going to take the first one.

KimGarbade_1-1648033093387.png

Here it is in plain text:

return First(OrderBy(GroupBy((FeatureSetByName($datastore, 'TestPoints',['TxtTest'],false)), 'TxtTest',{name: 'NumberTest', expression: '1', statistic: 'COUNT'}),'NumberTest DESC')).TxtTest

Hope this helps.

K

0 Kudos
KimGarbade
Occasional Contributor III

Maybe no one is reading this one anymore, but I revisited it.

I couldn't stop thinking about this one so I gave it a go in a Dashboard and it turned out to be much harder than I thought it would be.  I couldn't figure out how to do it just using GroupBy and OrderBy when in the Dashboard environment (long story but I couldn't get my Total Incidents, Predominant Incident Type, and Incident Name all in the same FeatureSet using this method... not saying its not possible.  I just couldn't figure it out). 

Then I found this great sample on github:

arcade-expressions/CombineMultipleLayers(SerialChart).md at master · Esri/arcade-expressions · GitHu...

 Wow... Very cool!  It shows you how to return your own custom FeatureSet from a dictionary. 

Using these two fields in my sample data:

KimGarbade_0-1648505435390.png

And this code to define the data source to use for my list:

// Write an expression that returns a FeatureSet.
// Documentation: https://arcg.is/3c419TD
// Samples: https://arcg.is/38SEWWz

//----------------------------------------------------------
//Portal feature set
//----------------------------------------------------------
var IncidentsByCounty = GroupBy(FeatureSetByPortalItem(Portal('https://garbadehome.maps.arcgis.com'),'baa95b02c52147bf8962379e85831fe8',0,['County','Incident'], True), 
  [ //fields/expressions to group statistics by
    {name: 'County', expression: 'County'},
    {name: 'Incident', expression: 'Incident'}
  ],
  [ // statistics to return for each unique categroy
    {name: 'CountOfInc', expression: 'Incident', statistic: 'COUNT'}
  ]
)

var cntyNoIncident = GroupBy(IncidentsByCounty, 
  [ //fields/expressions to group statistics by
    {name: 'County', expression: 'County'}
  ],
  [ // statistics to return for each unique categroy
    {name: 'Predom', expression: 'CountOfInc', statistic: 'MAX'},
    {name: 'TotalInc', expression: 'CountOfInc', statistic: 'SUM'}
  ]
)

// Create empty array for features, feat object to populate array
var features = [];
var feat;

for(var cnty in cntyNoIncident){
    var countyname = cnty.County
    var predomCount = cnty.Predom
    var incidentTotal = cnty.TotalInc
    var predomIncType = filter(IncidentsByCounty,"County = @countyname AND CountOfInc = @predomCount")
    var x = []
    for (var topIncident in predomIncType){
      Push (x, topIncident.Incident)
    }
    feat = {  
        attributes: {
            County: countyname,
            PredomIncidentType: Concatenate(x,'/'),
            PredomIncidentTotal: predomCount,
            TotalIncidents: incidentTotal,
        },
    }
    Push(features, feat);
}

var outputDict = {
    fields: [
        {name: 'County', type: 'esriFieldTypeString'},
        {name: 'PredomIncidentType', type: 'esriFieldTypeString'},
        {name: 'PredomIncidentTotal', type: 'esriFieldTypeInteger'},
        {name: 'TotalIncidents', type: 'esriFieldTypeInteger'},
    ],
    geometryType: '',
    features: features,
}

return FeatureSet(Text(outputDict));
//return predomIncType

I generated this List:

KimGarbade_1-1648505612306.png

I learned a bunch so thank you for the question.

K

0 Kudos
cwlee27
New Contributor II

Kim - thank you so much, this is great! I'm going to try to implement this on my end, I'll let you know how it goes!

0 Kudos