Hi . I am trying to understand how to build a data expression for a list view in a dashboard where the output of two geometric expressions should pupulate into a FeatureSet. I am creating a buffer and intersect between two layers and if the condition satisfies, the output should return a text value within the FeatureSet.
This works while configuring pop ups but do not know how to populate this for a list view with dashboards.
Scripts looks something like this while configuring pop ups.
if(!IsEmpty(int1)) {
return Proper(`Affected by ${int1.Event}.`)
}
else {
return "Not affected by Event"
}
How would I show this output on a FeatureSet. Is this possible here?
Solved! Go to Solution.
I see a "First" at the top of your code (which means you're working with one feature) and I'm not sure what the intention is there. That would be useful if you wanted to take the first feature in a featureset, but you'll need to go through all your features if I'm understanding correctly.
I would also create something (like a dictionary) to hold the output before you start "creating" the output (doing the intersection), if that makes sense? I also don't think you need all those Text functions in Push if those are already strings?
Also, you show the results of your code which does have the "status" field, but I think in the next screenshot (your dashboard list), you're wondering why you're only seeing the census tract name? That would be down to how your list is formatted, not the code.
Here's an example of what I think you're trying to do, but with the Living Atlas current wildfires layer and the ACS population layer. For each state, I want to list the wildfires that affect that state:
// Get source featuresets
var wildfiresFS = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), 'd957997ccee7408287a963600a77f61f', 1, ['IncidentName'], true)
var stateFS = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), 'f430d25bf03744edbb1579e18c4bf6b8', 0, ['Name'], true)
// Create a dictionary for the output
var outputDict = {fields: [
{name: 'StateName', type: 'esriFieldTypeString'},
{name: 'IncidentsName', type: 'esriFieldTypeString'}],
geometryType: '',
features: []
}
// Loop through each state and see if it's affected by any wildfires
for (var i in stateFS){
// Create variables to hold the name of the wildfire(s) and how long the name is, since I'll need to tidy that up later
var wildfiresTxt
var wildfiresTxtCount
// Loop through each fire, and if it affects the state, list it
for (var fire in wildfiresFS){
if (Intersects(fire, i)){
wildfiresTxt += fire.IncidentName + ", "
wildfiresTxtCount = Count(wildfiresTxt)
}
}
// Write results
Push(outputDict['features'], {attributes: {StateName: i.Name, IncidentsName: Left(wildfiresTxt, wildfiresTxtCount-2)}})
}
var fsNew = FeatureSet(Text(outputDict))
return fsNew
Here's the result (Arizona is a little weird because at the moment there's one fire without a name, and I'd rather the states without fires just be null, but this is just an example):
Here's where you can add more fields to your list presentation:
FeatureSetByPortalItem is not supported in Dashboards lists. Only the Core function bundle is supported (Dashboard List Formatting | ArcGIS Arcade | Esri Developer).
Hi @AndreasHall . Seems that it is supported.
In case of something like this
And example would be (using a living atlas layer here)
Okay, I might be wrong. Arcade is not my field of expertise.
I think the problem/difference is that for your pop-ups, what's being returned is the result for one feature, whereas for your list, you need the whole featureset, so you need to store your results in a new featureset and return that featureset. You can use a dictionary to do this. The example shows a lot of options, but you don't need to actually set all those up. The basic way is to just set up your fields (in this case, I didn't need geometry):
var newDict = {fields: [
{name: 'NAME', type: 'esriFieldTypeString'},
{name: 'CENSUS0', type: 'esriFieldTypeInteger'},
{name: 'CENSUS1', type: 'esriFieldTypeInteger'},
{name: 'REGION', type: 'esriFieldTypeString'}],
geometryType: '',
features: []
}
After you create this, loop through the featureset(s) that are going to populate your new featureset. In this (heavily abbreviated) example, I wanted to add a "region" field to some ACS data on Living Atlas. This would be where your "affected by event"/"not affected by event" stuff goes:
for (var i in fsMI){ // This is the featureset I'm starting with, that doesn't have all the fields I need
var region
When(
i.NAME=="esrdfgbtdgbfd", region = '1',
i.NAME=="seihfirkesj", region = '8',
region = '0'
)
// Now that I have my regions, I can take the dictionary I created earlier and use it to fill my new featureset
Push(newDict['features'], {attributes: {NAME: i.NAME, CENSUS0: i[censusField0], CENSUS1: i[censusField1], REGION: region}})
}
var fsMINew = FeatureSet(Text(newDict))
Thanks for looking into this. Unfortunatly I am still not very clear on how to implement the dictionary function.
For example the first part of my code would run the geometric/spatial operation
var fs1 = FeatureSetByPortalItem(Portal('https://www.arcgis.com'),'a6134ae01aad44c499d12feec782b386',6,['Event', 'Severity','Certainty', 'Summary','Updated', 'Start', 'End_'],false); //polygon layer
var fs2 = FeatureSetByPortalItem(Portal('https://www.arcgis.com'),'f430d25bf03744edbb1579e18c4bf6b8',2,['Name', 'State','County', 'B01001_001E'],false); //polygon layer
var int1 = First(Intersects(fs1, fs2))
In my next step I will have to declare the fields I will be using to update the output by building a dictionary from the second ACS feature service (fs2). In this case I have delcared a new field named STATUS (as you had defined Region) to show the "Affected by/not Affected by " statement.
var newDict = {fields: [
{name: 'NAME', type: 'esriFieldTypeString'},
{name: 'STATE', type: 'esriFieldTypeString'},
{name: 'COUNTY', type: 'esriFieldTypeString'},
{name: 'STATUS', type: 'esriFieldTypeString'}],
geometryType: '',
features: []
}
Now I shall have to loop through the featureset(s) and populate the new featureset. In this case I wanted to use the output of the intersect operation. I used the When function but could I stick to an if else loop?
for (var i in fs2){
var status
When(
!IsEmpty(int1), status = `Affected by ${int1.Event}.`,
IsEmpty(int1), status = `Not Affected.`
)
Push(newDict['features'], {attributes: {NAME: i.NAME, STATE: i.STATE, COUNTY: i.COUNTY, STATUS: status}})
}
var fs2New = FeatureSet(Text(newDict))
In this case I do get an error while writing the When function.
I did also use something like this
for (var i in fs2){
var status
When(
i.STATE=="Alabama", status = `Affected by ${int1.Event}.`,
i.STATE=="Alaska", status = `Affected by ${int1.Event}.`,
status = `Not Affected.`
)
Push(newDict['features'], {attributes: {NAME: i.NAME, STATE: i.STATE, COUNTY: i.COUNTY, STATUS: status}})
}
var fs2New = FeatureSet(Text(newDict))
return fs2New
In this case it asks me to verify my test data. I am using both livingatlas layers in this case.
I also did explore the case of adding the When conditions as an expression as outlined within the Distinct function of the FeatureSet.
e.g.
Distinct($layer, { name: "Density", expression: "CASE WHEN PopDensity < 100 THEN 'Low' WHEN PopDensity >= 100 THEN 'High' ELSE 'N/A' END" })
Thanks again for all your help. I think we're very close and I am making a mistake due to my lack of knowledge on featuresets.
I also did try another approach. Seemed a bit clearer to me and it also does provide an output but just one record.
var fields1= ['Event', 'Severity','Certainty', 'Summary','Updated', 'Start', 'End_'];
var fields2= ['Name', 'State','County'];
var fs1 = FeatureSetByPortalItem(Portal('https://www.arcgis.com'),'a6134ae01aad44c499d12feec782b386',6,fields1,false); //polygon layer
var fs2 = FeatureSetByPortalItem(Portal('https://www.arcgis.com'),'f430d25bf03744edbb1579e18c4bf6b8',2,fields2,false); //polygon layer
//Ran the intersect
var int1 = First(Intersects(fs1, fs2))
var features =[];
//looping through intersect condition
for (var f in fs2) {
var i = First(Intersects(fs1, f))
if (!IsEmpty(i)) {
var status = `Affected by ${int1.Event}.`
} else {
status = `Not Affected.`
}
}
Push(features,
{
attributes:
{
Name: Text(f["Name"]),
State: Text(f["State"]),
County: Text(f["County"]),
status: Text(status)
}
});
//creating an output table
var table = {
'fields' :[
{
name: "Name",
alias: "Name",
type: "esriFieldTypeString"
},
{
name: "State",
alias: "State",
type: "esriFieldTypeString"
},
{
name: "County",
alias: "County",
type: "esriFieldTypeString"
},
{
name: "status",
alias: "status",
type: "esriFieldTypeString"
},
],
geometryType: "",
features: features
}
return FeatureSet(table);
Output:
Unfortunatly I get only one record with a single FID.
Should'nt I be getting all the records within the ACS county layer. Would be great if you could help with the loop
I see a "First" at the top of your code (which means you're working with one feature) and I'm not sure what the intention is there. That would be useful if you wanted to take the first feature in a featureset, but you'll need to go through all your features if I'm understanding correctly.
I would also create something (like a dictionary) to hold the output before you start "creating" the output (doing the intersection), if that makes sense? I also don't think you need all those Text functions in Push if those are already strings?
Also, you show the results of your code which does have the "status" field, but I think in the next screenshot (your dashboard list), you're wondering why you're only seeing the census tract name? That would be down to how your list is formatted, not the code.
Here's an example of what I think you're trying to do, but with the Living Atlas current wildfires layer and the ACS population layer. For each state, I want to list the wildfires that affect that state:
// Get source featuresets
var wildfiresFS = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), 'd957997ccee7408287a963600a77f61f', 1, ['IncidentName'], true)
var stateFS = FeatureSetByPortalItem(Portal('https://www.arcgis.com'), 'f430d25bf03744edbb1579e18c4bf6b8', 0, ['Name'], true)
// Create a dictionary for the output
var outputDict = {fields: [
{name: 'StateName', type: 'esriFieldTypeString'},
{name: 'IncidentsName', type: 'esriFieldTypeString'}],
geometryType: '',
features: []
}
// Loop through each state and see if it's affected by any wildfires
for (var i in stateFS){
// Create variables to hold the name of the wildfire(s) and how long the name is, since I'll need to tidy that up later
var wildfiresTxt
var wildfiresTxtCount
// Loop through each fire, and if it affects the state, list it
for (var fire in wildfiresFS){
if (Intersects(fire, i)){
wildfiresTxt += fire.IncidentName + ", "
wildfiresTxtCount = Count(wildfiresTxt)
}
}
// Write results
Push(outputDict['features'], {attributes: {StateName: i.Name, IncidentsName: Left(wildfiresTxt, wildfiresTxtCount-2)}})
}
var fsNew = FeatureSet(Text(outputDict))
return fsNew
Here's the result (Arizona is a little weird because at the moment there's one fire without a name, and I'd rather the states without fires just be null, but this is just an example):
Here's where you can add more fields to your list presentation: