ArcGIS Dashboard Data Expression, "unable to execute Arcade script"

8819
27
Jump to solution
04-28-2021 09:14 AM
erica_poisson
Occasional Contributor III

Hi,

I am very new to Arcade (which you probably be able to tell by my filter expressions below).

I am attempting to create a Data Expression that can be used to power an Indicator widget in a Dashboard. I have built and tested this in the Data Expression builder within my Dashboard and when I click "test" it returns the proper result. I click done, but then see a little triangle with an ! telling me "Unable to execute Arcade script".

Why would I see this message? My Arcade script is below. Any help would be appreciated. 

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;

var fs1 = FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false);

var filterCMpts = Filter(fs1, "Point_Status ='Unstable' AND EQ_File_Number ='EQ2015-078' OR Point_Status ='Unstable' AND  EQ_File_Number = 'Eq2013-026' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2018-082' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2018-052' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2001-080X' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2003-021' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ1989-015' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2002-023' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2002-045X' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2019-110' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2020-017' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2019-091' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2018-029' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2020-033' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2019-036' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2020-052' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2019-064' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2017-040' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2020-031' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2021-003' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2011-016' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2017-026' OR Point_Status ='Unstable' AND  EQ_File_Number = 'EQ2021-020'");

var itemID_join = 'xxx';
var layerID_join = 0;

var fs2 = FeatureSetByPortalItem(Portal(p), itemID_join, layerID_join, ['Point_Status_revisit', 'EQ_File_Number'], false);

var filterJoin = Filter(fs2, "Point_Status_revisit ='Stable' AND EQ_File_Number ='EQ2015-078' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'Eq2013-026' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2018-082' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2018-052' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2001-080X' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2003-021' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ1989-015' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2002-023' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2002-045X' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2019-110' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2020-017' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2019-091' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2018-029' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2020-033' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2019-036' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2020-052' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2019-064' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2017-040' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2020-031' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2021-003' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2011-016' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2017-026' OR Point_Status_revisit ='Stable' AND  EQ_File_Number = 'EQ2021-020'");

var CntCMpts = Count(filterCMpts)
var CntJoin = Count(filterJoin)

return CntCMpts - CntJoin

 

Thank you! 

Erica
0 Kudos
2 Solutions

Accepted Solutions
XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson  and @KenBuja ,

You actually can return an in-memory featureset with the data that you want to graph. Since I am not sure what you are exactly after I will provide an example and you can adjust accordingly.

See the example below (please note that the filter expression is using the syntax suggested by Ken). The first part is pretty much the same, but after getting the counts, you create a schema for the output featureset, and fill it with the data. In this case, it will be a featureset with 3 fields and only 1 row. This can be used in the Dashboard as data source. 

 

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var itemID_join = 'xxx';
var layerID_join = 0;

var fs1 = FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false);
var filterCMpts = Filter(fs1, "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', etc)" );

var fs2 = FeatureSetByPortalItem(Portal(p), itemID_join, layerID_join, ['Point_Status_revisit', 'EQ_File_Number'], false);
var filterJoin = Filter(fs2, "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', etc)");

var CntCMpts = Count(filterCMpts);
var CntJoin = Count(filterJoin);

// create data schema
var Dict = {
    'fields': [
        {'name': 'CntCMpts', 'type': 'esriFieldTypeInteger'},
        {'name': 'CntJoin', 'type': 'esriFieldTypeInteger'},
        {'name': 'CntCMptsMinusCntJoin', 'type': 'esriFieldTypeInteger'}],
    'geometryType': '',   
    'features': []};

// fill the data schema with the data
Dict.features[0] = {
            'attributes': {
                'CntCMpts': CntCMpts,
                'CntJoin': CntJoin,
                'CntCMptsMinusCntJoin': CntCMpts - CntJoin
            }}

// return the featureset
return FeatureSet(Text(Dict));

 

 

View solution in original post

XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson ,

That is interesting. It returns the correct value, but it does show an error. Maybe the name for the relationshipclass that should be used has to be "Construction_Monitoring_Revisit" (I am not sure). The best way to validate this is to add the layer to the map and use the navigation in the interface when creating an expression as described earlier. Just to be sure that you are using the correct name.

I am also wondering if it is enough to return the count as a number or that a featureset is expected. I think the latter. In that case, you could use something like the expression below.

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var relationshipName = "Construction_Monitoring_Revisit";

var fs1 = Filter(FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false), "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', 'EQ2018-052', 'EQ2001-080X', 'EQ2003-021', 'EQ1989-015', 'EQ2002-023', 'EQ2002-045X', 'EQ2019-110', 'EQ2020-017', 'EQ2019-091', 'EQ2018-029', 'EQ2020-033', 'EQ2019-036', 'EQ2020-052', 'EQ2019-064', 'EQ2017-040', 'EQ2020-031', 'EQ2021-003', 'EQ2011-016', 'EQ2017-026', 'EQ2021-020')");

var tot = 0;
for (var f in fs1) {
    var fs2 = FeatureSetByRelationshipName(f, relationshipName, ['Point_Status_revisit'], false);
    var cnt = Count(fs2);
    if (cnt == 0) {
        tot += 1;
    }
}

// return tot;

// create data schema
var Dict = {
    'fields': [
        {'name': 'CountNoAttach', 'type': 'esriFieldTypeInteger'}],
    'geometryType': '',   
    'features': []};

// fill the data schema with the data
Dict.features[0] = {
            'attributes': {
                'CountNoAttach': tot
            }}

// return the featureset
return FeatureSet(Text(Dict));

 

View solution in original post

27 Replies
KenBuja
MVP Esteemed Contributor

Data expressions generate a FeatureSet, so that's all you can return, not the count of your two FeatureSets.

A note about your SQL statement.  You can make it much shorter using this format

"Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', etc)" 

 

XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson  and @KenBuja ,

You actually can return an in-memory featureset with the data that you want to graph. Since I am not sure what you are exactly after I will provide an example and you can adjust accordingly.

See the example below (please note that the filter expression is using the syntax suggested by Ken). The first part is pretty much the same, but after getting the counts, you create a schema for the output featureset, and fill it with the data. In this case, it will be a featureset with 3 fields and only 1 row. This can be used in the Dashboard as data source. 

 

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var itemID_join = 'xxx';
var layerID_join = 0;

var fs1 = FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false);
var filterCMpts = Filter(fs1, "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', etc)" );

var fs2 = FeatureSetByPortalItem(Portal(p), itemID_join, layerID_join, ['Point_Status_revisit', 'EQ_File_Number'], false);
var filterJoin = Filter(fs2, "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', etc)");

var CntCMpts = Count(filterCMpts);
var CntJoin = Count(filterJoin);

// create data schema
var Dict = {
    'fields': [
        {'name': 'CntCMpts', 'type': 'esriFieldTypeInteger'},
        {'name': 'CntJoin', 'type': 'esriFieldTypeInteger'},
        {'name': 'CntCMptsMinusCntJoin', 'type': 'esriFieldTypeInteger'}],
    'geometryType': '',   
    'features': []};

// fill the data schema with the data
Dict.features[0] = {
            'attributes': {
                'CntCMpts': CntCMpts,
                'CntJoin': CntJoin,
                'CntCMptsMinusCntJoin': CntCMpts - CntJoin
            }}

// return the featureset
return FeatureSet(Text(Dict));

 

 

XanderBakker
Esri Esteemed Contributor

Below an example of the featureset that will be returned using some random values for the counts:

XanderBakker_0-1620075312396.png

 

0 Kudos
erica_poisson
Occasional Contributor III

Hi Xander,

Thank you for the example. I was able to get this to work using something I came up with that basically does what you showed in the example. Unfortunately, this is not quite what I need after reflecting on the results. 

What I really want to be able to do is get the count of records in my point layer that do not have any related records associated with them. Is that possible using the FeatureSetByRelationshipName parameter? I've seen some other posts you have responded to around FeatureSetByRelationshipName, but none of the examples talk about doing something like what I am trying to accomplish. 

Thank you,

 

Erica
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson ,

I just had a look in the list of functions available when creating an Arcade data expression. For instance, the Attachments function is not available, but FeatureSetByRelationshipName is. I assume you published your data and related data with a relationship class. If this is not the case, you can still use the filter function to get the same result. The performance will depend greatly on the number of features you have since a loop through all features is required to get this result.

Based on the sample expression you shared, have a look at the expression below:

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var relationshipName = "the name of the relationship between data and related data";

var fs1 = FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false);

var tot = 0;
for (var f in fs1) {
    var fs2 = FeatureSetByRelationshipName(f, relationshipName, ['DummyField'], false);
    var cnt = Count(fs2);
    if (cnt == 0) {
        tot += 1;
    }
}

return tot;

 

In this example for each feature the related features are queried and if the count is 0, the total is incremented by one. At the end you should have the number of features that have no related records.

 

0 Kudos
erica_poisson
Occasional Contributor III

I will give this a try tomorrow morning. One question...the relationship name that I put in there, is it the name of the relationship class in the fGDB from pre-publishing to AGOL?

Erica
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson ,

Good question... Normally, when you edit an Arcade expression you will have access to the properties and the easiest way is navigating the interface to use the relationship. Let me visualize this.

In the expression editor you would find the $feature on the right and you can enter and find all the fields of this $feature (click on ">" in blue rectangle):

XanderBakker_0-1620157139052.png

Next, at the end of the list of attributes you would find "Related records" and you can see all the relationships (click on ">" in blue rectangle)

XanderBakker_1-1620157274001.png

This will show the relationship and when you click on the "FeatureSetByRelationshipName" link it will be correctly inserted in the code. 

However, since you access the data in the data expression using the "FeatureSetByPortalItem" you will not find those options in the interface. 

You can go to the details page of the hosted feature layer and open the REST end point:

XanderBakker_2-1620157438189.png

In the REST endpoint page at the end, you will find the relationships section with the name of the relationship:

XanderBakker_3-1620157499282.png

 

 

 

0 Kudos
erica_poisson
Occasional Contributor III

@XanderBakker 

Ah I see. I am perplexed by my data. This was created via Pro with a named relationship class based on GlobalID/GUID, however this is what I see via the REST endpoint. I would have expected to see the relationship class name that I defined in Pro before I published these data to ArcGIS Online. 

erica_tefft_0-1620219376479.png

Out of curiosity, I added this layer to a new map and went into the pop-up to add a new expression. I clicked through $feature like you mentioned, found related records at the bottom and then clicked FeatureSetByRelationshipName to add it into the builder window. This is what I see. 

FeatureSetByRelationshipName($feature,"")

Here is the Arcade I attempted...I am now getting the "Unable to execute Arcade script" message again, even though it returns the correct number of records when I click "Test":

 

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var relationshipName = "";

var fs1 = Filter(FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false), "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', 'EQ2018-052', 'EQ2001-080X', 'EQ2003-021', 'EQ1989-015', 'EQ2002-023', 'EQ2002-045X', 'EQ2019-110', 'EQ2020-017', 'EQ2019-091', 'EQ2018-029', 'EQ2020-033', 'EQ2019-036', 'EQ2020-052', 'EQ2019-064', 'EQ2017-040', 'EQ2020-031', 'EQ2021-003', 'EQ2011-016', 'EQ2017-026', 'EQ2021-020')");

var tot = 0;
for (var f in fs1) {
    var fs2 = FeatureSetByRelationshipName(f, relationshipName, ['Point_Status_revisit'], false);
    var cnt = Count(fs2);
    if (cnt == 0) {
        tot += 1;
    }
}

return tot;

 

 

 

 

 

 

Erica
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi @erica_poisson ,

That is interesting. It returns the correct value, but it does show an error. Maybe the name for the relationshipclass that should be used has to be "Construction_Monitoring_Revisit" (I am not sure). The best way to validate this is to add the layer to the map and use the navigation in the interface when creating an expression as described earlier. Just to be sure that you are using the correct name.

I am also wondering if it is enough to return the count as a number or that a featureset is expected. I think the latter. In that case, you could use something like the expression below.

var p = 'https://www.arcgis.com';
var itemID_CMpts = 'xxx';
var layerID_CMpts = 0;
var relationshipName = "Construction_Monitoring_Revisit";

var fs1 = Filter(FeatureSetByPortalItem(Portal(p), itemID_CMpts, layerID_CMpts, ['Point_Status', 'EQ_File_Number'], false), "Point_Status ='Unstable' AND EQ_File_Number In ('EQ2015-078', 'Eq2013-026', 'EQ2018-082', 'EQ2018-052', 'EQ2001-080X', 'EQ2003-021', 'EQ1989-015', 'EQ2002-023', 'EQ2002-045X', 'EQ2019-110', 'EQ2020-017', 'EQ2019-091', 'EQ2018-029', 'EQ2020-033', 'EQ2019-036', 'EQ2020-052', 'EQ2019-064', 'EQ2017-040', 'EQ2020-031', 'EQ2021-003', 'EQ2011-016', 'EQ2017-026', 'EQ2021-020')");

var tot = 0;
for (var f in fs1) {
    var fs2 = FeatureSetByRelationshipName(f, relationshipName, ['Point_Status_revisit'], false);
    var cnt = Count(fs2);
    if (cnt == 0) {
        tot += 1;
    }
}

// return tot;

// create data schema
var Dict = {
    'fields': [
        {'name': 'CountNoAttach', 'type': 'esriFieldTypeInteger'}],
    'geometryType': '',   
    'features': []};

// fill the data schema with the data
Dict.features[0] = {
            'attributes': {
                'CountNoAttach': tot
            }}

// return the featureset
return FeatureSet(Text(Dict));