Hello,
I'm new to Arcade and even newer to creating Data Expressions in Dashboards. I have three fields that I can populate using Arcade in my AGO web map Configure Pop-Ups section. Unfortunately, as we all know, these type of calculated fields do not show up in Dashboards and Globals are not present. I've been reading over past postings and it seems the key for me would be to employ FeatureSetByPortalItem() and create a data expression inside Dashboards so this data can be used. The three fields are Temporal Block, Hour, and Weekday.
The code I'm using in AGO for Temporal Block is:
var t = Hour($feature.PresentDate);
When(
t >= 22 || t < 6, "Night (10pm - 6am)",
t >= 6 && t < 11, "Morning (6am - 11am)",
t >= 11 && t < 13, "Midday (11am - 1pm)",
t >= 13 && t < 17, "Afternoon (1pm - 5pm)",
t >= 17 && t < 22, "Evening (5pm - 10pm)",
"Invalid date" );
The code I'm using in AGO for Hour is:
Hour($feature.PresentDate)
And the code I am using in AGO for Weekday is:
Weekday($feature.PresentDate)
Can someone please help me or give me some hints at how to create an Arcade expression employing FeatureSetByPortalItem that will perform these calculations inside Dashboard?
Thank you so much in advance.
Jeff
Solved! Go to Solution.
You'll want to check out the Arcade GitHub repo for lots of examples.
If all you want is to get those three items into your Data Expression, that's easy enough. The basic things to know about data expressions are the FeatureSetByPortalItem function to get your inputs, and then the basic structure of a FeatureSet's JSON definition so that you can build your own.
Also, just a side note: when you've got multiple conditions, they evaluate in order. So anything that fails to meet the ">= 22" condition will be less than 22 (or null) by definition, so you don't need to later use "< 22". Especially when you're using a numeric value, you can just evaluate in ascending or descending order.
And a side side note: since you're working with the hours field and one of your decoded strings spans the midnight mark, you can get that into a single condition by using the modulo (%) operator. Put another way, 23 % 22 = 1. So in the initial condition in that when function, we can use that to reduce the >= 22 hours to a small number that will be caught in the same condition.
var portal = Portal('your portal url')
var fs = FeatureSetByPortalItem(
portal,
'itemID of your service',
0, // or whatever the layer index is
['PresentDate', 'any', 'other', 'fields', 'you', 'want'],
false // unless you really need geometry, but it performs much better without
)
// Create a dictionary to hold our output
var out_dict = {
fields: [
{name: 'PresentDate', type: 'esriFieldTypeDate'},
{name: 'Weekday', type: 'esriFieldTypeString'},
{name: 'Hour', type: 'esriFieldTypeInteger'},
{name: 'TimeString', type: 'esriFieldTypeString'}
// include any other fields you want in the output here
],
geometryType: '',
features: []
}
// Iterate over features, calculate new fields, push to dictionary
for (var f in fs){
var t = Hour(f['PresentDate'])
var time_str = When(
(t % 22) < 6, "Night (10pm - 6am)",
t < 11, "Morning (6am - 11am)",
t < 13, "Midday (11am - 1pm)",
t < 17, "Afternoon (1pm - 5pm)",
t < 22, "Evening (5pm - 10pm)",
t < 24, "Night (10pm - 6am)",
"Invalid date"
)
var wkday = Weekday(f['PresentDate'])
Push(
out_dict['features'],
{
attributes: {
PresentDate: f['PresentDate'],
Weekday: wkday,
Hour: t,
TimeString: time_str
}
}
)
}
return FeatureSet(Text(out_dict))
It looks like a lot, but once you get the basic syntax down, it's not that bad.
You'll want to check out the Arcade GitHub repo for lots of examples.
If all you want is to get those three items into your Data Expression, that's easy enough. The basic things to know about data expressions are the FeatureSetByPortalItem function to get your inputs, and then the basic structure of a FeatureSet's JSON definition so that you can build your own.
Also, just a side note: when you've got multiple conditions, they evaluate in order. So anything that fails to meet the ">= 22" condition will be less than 22 (or null) by definition, so you don't need to later use "< 22". Especially when you're using a numeric value, you can just evaluate in ascending or descending order.
And a side side note: since you're working with the hours field and one of your decoded strings spans the midnight mark, you can get that into a single condition by using the modulo (%) operator. Put another way, 23 % 22 = 1. So in the initial condition in that when function, we can use that to reduce the >= 22 hours to a small number that will be caught in the same condition.
var portal = Portal('your portal url')
var fs = FeatureSetByPortalItem(
portal,
'itemID of your service',
0, // or whatever the layer index is
['PresentDate', 'any', 'other', 'fields', 'you', 'want'],
false // unless you really need geometry, but it performs much better without
)
// Create a dictionary to hold our output
var out_dict = {
fields: [
{name: 'PresentDate', type: 'esriFieldTypeDate'},
{name: 'Weekday', type: 'esriFieldTypeString'},
{name: 'Hour', type: 'esriFieldTypeInteger'},
{name: 'TimeString', type: 'esriFieldTypeString'}
// include any other fields you want in the output here
],
geometryType: '',
features: []
}
// Iterate over features, calculate new fields, push to dictionary
for (var f in fs){
var t = Hour(f['PresentDate'])
var time_str = When(
(t % 22) < 6, "Night (10pm - 6am)",
t < 11, "Morning (6am - 11am)",
t < 13, "Midday (11am - 1pm)",
t < 17, "Afternoon (1pm - 5pm)",
t < 22, "Evening (5pm - 10pm)",
t < 24, "Night (10pm - 6am)",
"Invalid date"
)
var wkday = Weekday(f['PresentDate'])
Push(
out_dict['features'],
{
attributes: {
PresentDate: f['PresentDate'],
Weekday: wkday,
Hour: t,
TimeString: time_str
}
}
)
}
return FeatureSet(Text(out_dict))
It looks like a lot, but once you get the basic syntax down, it's not that bad.
Thank you so much Josh! I really appreciate your help.
Jeff
Oh! Right! I completely forgot to mention, but data expressions don't like "naked" date values, and it returns an empty FeatureSet when it encounters them. To get around this, we need to dress up the date as a number.
Try replacing line 44 of the above expression with this:
PresentDate: Number(f['PresentDate'])
That should get you what you need.
That did it. Thank you, Josh.
One quick additional related question...I would like to be able to add one more field, CrimeEntry, to the data available. Am I understanding that I would need to add the CrimeEntry field after 'PresentDate' following FeatureSetByPortalItem, add it as a field in the out_dict fields section, call it out as a var for the iterate over features section, and then list it within out_dict for attributes section to see the corresponding crimes reported for that particular date?
Hope that makes sense...novice here...terminology escapes.
Jeff
First, I'd like to thank Josh Carlson for the big assist and the Community Forum in general for being such a great resource to GIS professionals. Truly outstanding. Secondly, I just wanted to post a follow-up to my last question. I was able to add CrimeEntry to the original code which allowed me to associate temporal data with the particular crime reported at that given time and day. The following is the modified data expression to achieve this result:
//Set which data I want to use with what fields I want as part of my output
var portal = Portal('your portal')
var fs = FeatureSetByPortalItem(
portal,
'your itemID',
0, ['PresentDate', 'CrimeEntry'],
false // unless you really need geometry, but it performs much better without
);
// Create an empty dictionary to hold our output
var out_dict = {
fields: [
{name: 'PresentDate', type: 'esriFieldTypeDate'},
{name: 'CrimeEntry', type: 'esriFieldTypeString'},
{name: 'Weekday', type: 'esriFieldTypeInteger'},
{name: 'Hour', type: 'esriFieldTypeInteger'},
{name: 'TimeString', type: 'esriFieldTypeString'}
// include any other fields you want in the output here
],
geometryType: '',
features: []
}
// Iterate over features, calculate new fields, push to dictionary
for (var f in fs){
var t = Hour(f['PresentDate'])
var time_str = When(
(t % 22) < 6, "Night (10pm - 6am)",
t < 11, "Morning (6am - 11am)",
t < 13, "Midday (11am - 1pm)",
t < 17, "Afternoon (1pm - 5pm)",
t < 22, "Evening (5pm - 10pm)",
t < 24, "Night (10pm - 6am)",
"Invalid date"
)
var wkday = Weekday(f['PresentDate'])
Push(
out_dict['features'],
{
attributes: {
PresentDate: Number(f['PresentDate']),
CrimeEntry: (f['CrimeEntry']),
Weekday: wkday,
Hour: t,
TimeString: time_str
}
}
)
}
return FeatureSet(Text(out_dict))