Select to view content in your preferred language

Creating an indicator to show worker attendance

199
5
Jump to solution
2 weeks ago
ryanEvanczyk
Frequent Contributor

We use a dashboard for employee performance reviews for the end of our ski season. Info for this dashboard comes from a daily record survey we fill out every morning saying who is on duty, who called out sick, who is off campus for a work thing, etc. 

The survey questions are multiple select type. I can't seem to get the indicator to accurately show the number of times a name has been selected in the survey results for the questions. Adjusting the data to show the statistic as a count for the "On duty" field yields "0" in the indicator unless the selected name is the only answer selected for a date. For example, when the employees are selected for the "On duty" question, which always has more than one name selected for the multiple select question type, the indicator does not single out how many times a name is selected for this field when the dashboard is filtered by name using the category selector in the header. Is there any way to fix this so the indicator can read every instance a name is selected whether they are the only selection or not? 

0 Kudos
1 Solution

Accepted Solutions
MobiusSnake
MVP Regular Contributor

You'll want to create a Data Expression that splits comma-delimited values into multiple strings, then create one feature in your Data Expression for each split part.

Here's a contrived example, I took the scoresheet from the Toronto-Ottawa game last night and put it into a table with a single field, the field has the goal scorer and players that assisted, comma-delimited:

Screenshot 2025-04-28 025236.png

Unassisted goals only have a single name, assisted goals may have two or three names.

For the indicator I want to display total points, so I'll want to expand this out to sixteen records (one record per point), this Arcade will do it:

var myPortal = Portal("https://(org_name).maps.arcgis.com");
var scoresheetFeatureSet = FeatureSetByPortalItem(myPortal, "(item_id)", 0, ["points"]);

// Iterate through the records, splitting each into separate records for each part.
var playerFeatures = [];
for (var scoresheetFeature in scoresheetFeatureSet) {
  var pointsCsv = scoresheetFeature["points"];
  var pointsNames = Split(pointsCsv, ",");
  for (var nameIdx in pointsNames) {
    var playerFeature = {attributes: {name: pointsNames[nameIdx]}};
    Push(playerFeatures, playerFeature);
  }
}

// Create a feature set from the features list.
var returnFeatureSetDict = {
  fields: [{ name: "name", type: "esriFieldTypeString" }],
  "geometryType": "",
  "features": playerFeatures
};
return FeatureSet(Text(returnFeatureSetDict));

 

You'll probably want to have your employee names coming from a separate "master list" table, and have a List element driven by that.  Create an action that filters the indicator's Data Expression on your List selection.  I did this and here's what it looks like when I click on J. Sanderson, who had two points last night:

Screenshot 2025-04-28 025833.png

This is probably the simplest approach, but you could also create a Data Expression that has two fields, name and attendance count, and instead of simply creating a list of names, you could create a dictionary of counts, and return a distinct list of names with a count beside each one.  This could let you do some cool things like pulling in additional info about the person from other sources, but may not work so well if you have someone with an attendance of zero.

View solution in original post

0 Kudos
5 Replies
MobiusSnake
MVP Regular Contributor

Is each indicator intended to be hard-coded to show a single person's days?  If so, I'm guessing you're trying to use the indicator's filter with the "equals" operator.  If that's the case, use the "contains" operator instead.

One downside of this approach, depending on how many names you have and how different they are from each other, is the possibility of one name being equal to a portion of another name.  Imagine if you had two people, one named "Steve Stevens" and another named "Steve Stevenson".  The contains operator would give you incorrect results for Steve Number 1.

If my assumption about the indicator's filter is wrong, and you're selecting a name from a list and trying to make the indicator react dynamically to that selection, that'll be a lot trickier with the output from a "select multiple" S123 question, but it's still possible (for example, by using Data Expressions).

ryanEvanczyk
Frequent Contributor

I was thinking a data expression would be the move here as I do want the indicator to react dynamically according to the category selector where the names are listed. I'm currently trying to figure out what the Arcade expression would be for this, as I haven't messed with composing code as much as tweaking existing code.

0 Kudos
MobiusSnake
MVP Regular Contributor

You'll want to create a Data Expression that splits comma-delimited values into multiple strings, then create one feature in your Data Expression for each split part.

Here's a contrived example, I took the scoresheet from the Toronto-Ottawa game last night and put it into a table with a single field, the field has the goal scorer and players that assisted, comma-delimited:

Screenshot 2025-04-28 025236.png

Unassisted goals only have a single name, assisted goals may have two or three names.

For the indicator I want to display total points, so I'll want to expand this out to sixteen records (one record per point), this Arcade will do it:

var myPortal = Portal("https://(org_name).maps.arcgis.com");
var scoresheetFeatureSet = FeatureSetByPortalItem(myPortal, "(item_id)", 0, ["points"]);

// Iterate through the records, splitting each into separate records for each part.
var playerFeatures = [];
for (var scoresheetFeature in scoresheetFeatureSet) {
  var pointsCsv = scoresheetFeature["points"];
  var pointsNames = Split(pointsCsv, ",");
  for (var nameIdx in pointsNames) {
    var playerFeature = {attributes: {name: pointsNames[nameIdx]}};
    Push(playerFeatures, playerFeature);
  }
}

// Create a feature set from the features list.
var returnFeatureSetDict = {
  fields: [{ name: "name", type: "esriFieldTypeString" }],
  "geometryType": "",
  "features": playerFeatures
};
return FeatureSet(Text(returnFeatureSetDict));

 

You'll probably want to have your employee names coming from a separate "master list" table, and have a List element driven by that.  Create an action that filters the indicator's Data Expression on your List selection.  I did this and here's what it looks like when I click on J. Sanderson, who had two points last night:

Screenshot 2025-04-28 025833.png

This is probably the simplest approach, but you could also create a Data Expression that has two fields, name and attendance count, and instead of simply creating a list of names, you could create a dictionary of counts, and return a distinct list of names with a count beside each one.  This could let you do some cool things like pulling in additional info about the person from other sources, but may not work so well if you have someone with an attendance of zero.

0 Kudos
ryanEvanczyk
Frequent Contributor

Your code worked! Thanks. 

0 Kudos
KimOllivier
Honored Contributor

Have you considered the GroupBy function in Arcade? This seems to be very useful to group multiple names and get a count.

0 Kudos