Select to view content in your preferred language

Arcade script to get intersection calculation

217
4
Jump to solution
3 weeks ago
Labels (1)
SarahHurley1
Occasional Contributor

I have a web map that includes the Watershed Boundary Dataset HUC 10s Living Atlas dataset. In Experience Builder, I need to use arcade to calculate the total area of each watershed that intersects with the USA Census States Living Atlas layer polygons (currently in the web map, but visibility is turned off). The purpose is to account for open water areas present within coastal watershed. I want the total land area of the watershed, minus the coastal open water outside of the states boundaries.

I am able to successfully do this in the popup arcade expressions within Map Viewer:

var states = Intersects(FeatureSetByName($map, "USA Census States"), $feature);
var cnt = Count(states);
var intersectArea = 0;

if (cnt > 0) {
    for (var st in states) {
        intersectArea += AreaGeodetic(Intersection($feature, st), "acres");
    } 
}


var acres = intersectArea

return Text(Round(acres, 2), "#,###.00");

 

However, in Experience Builder, the text widget arcade expressions do not support the "Intersection()" function. The Add Data via arcade option seems to support all these functions, but I am not able to get the arcade code to work and it does not show me where the errors are. This is the code I have in Add Data that is not working:

// returns the number of sensitive areas that intersect the selected feature
var p = Portal("https://arcgis.com");
var states = FeatureSetByPortalItem(p, "774019f31f8549c39b5c72f149bbe74e", 0);
var watershed = FeatureSetByPortalItem(p, "42f868d269784624b0a2df9757c34abb", 0);


var x = Intersects(states, watershed);
var cnt = Count(x);
var intersectArea = 0;

if (cnt > 0) {
    for (var st in states) {
        intersectArea += AreaGeodetic(Intersection(states, watershed), "acres");
    } 
}

var acres = Round(intersectArea,2);

return Text(Round(acres, 2), "#,###.00");

It just says "Test execution error: Execution error - Invalid parameter. Verify test data"

Ideally the goal is to not have to publish our own copies of these datasets (which would otherwise allow me to do all these calculations as a new field), and instead do the on the fly calculations off of the Living Atals datasets via arcade. 

 

Please let me know if you have any ideas. 

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
ShengdiZhang
Esri Regular Contributor

When adding data via Arcade, the expression needs to return a FeatureSet rather than a single value. Also, since acreage is calculated for each record in the watershed, that calculation should be placed inside the first loop.

However, this approach would require a nested loop. Even with filters applied to both the watershed and states layers, this still results in roughly 5,000 geometry calculations. This can make the initial load of the data very slow, and if network conditions are poor, the request may time out.

I recommend publishing a new dataset with an additional field for the acreage values. That said, if you’d like to try the Arcade method, here’s a sample script for reference:

var p = Portal("https://arcgis.com");
var states = FeatureSetByPortalItem(p, "774019f31f8549c39b5c72f149bbe74e", 0);
var watershed = FeatureSetByPortalItem(p, "42f868d269784624b0a2df9757c34abb", 0);

// Filter states and watershed to New England and New York
states = Filter(states, "STATE_ABBR IN ('ME', 'NH', 'VT', 'MA', 'RI', 'CT', 'NY')")
watershed = Filter(watershed, "states IN ('ME', 'NH', 'VT', 'MA', 'RI', 'CT', 'NY')");

var features = [];

for (var ws in watershed) {
  var intersectArea = 0;

  for (var st in states) {
    intersectArea += AreaGeodetic(Intersection(st, ws), "acres");
  }

  var acres = Round(intersectArea,2);

  Push(features, {
    attributes: {
      HUC10: ws.huc10,
      Acre: acres,
    }
  });
}

// Define schema for output FeatureSet (no geometry, only attributes)
var schema = {
    fields: [{
      name: "HUC10",
      alias: "HUC10",
      type: "esriFieldTypeString"
  }, {
    name: "Acre",
    alias: "Acre",
    type: "esriFieldTypeDouble"
  }],
  geometryType: "",
  features: features
};

return FeatureSet(schema);

You can try to improve performance by only intersecting each watershed record with the matching state polygon.

Thanks,

Shengdi

View solution in original post

0 Kudos
4 Replies
ShengdiZhang
Esri Regular Contributor

Hi @SarahHurley1 ,

Both states and watershed are feature sets. The Intersects function can’t take two feature sets directly — the second parameter needs to be a single feature.

ShengdiZhang_0-1754902726048.png

If you want to do this in Arcade, you’d need a loop like:

for (var ws in watershed) {
  x = Intersects(states, ws);
}

However, there would be a considerable performance issue with approximately 20,000 records in the watershed.

If the widget formatting profile supports Geometry bundle, you could use a text widget to show information for a selected watershed instead. That said, Geometry bundle support is still uncertain and not available yet.

Thanks,

Shengdi

0 Kudos
SarahHurley1
Occasional Contributor

Hi Shengdi, 

Thanks for looking into this. 

I do currently have the watershed layer filtered down to just 769 watershed records (just New England + New York), so hopefully that would help with performance. 

Maybe I misunderstood, but when I do this, it is still saying invalid script:

// returns the number of sensitive areas that intersect the selected feature
var p = Portal("https://arcgis.com");
var states = FeatureSetByPortalItem(p, "774019f31f8549c39b5c72f149bbe74e", 0);
var watershed = FeatureSetByPortalItem(p, "42f868d269784624b0a2df9757c34abb", 0);


for (var ws in watershed) {
  var x = Intersects(states, ws);
}
var cnt = Count(x);
var intersectArea = 0;

if (cnt > 0) {
    for (var st in states) {
        intersectArea += AreaGeodetic(Intersection(states, watershed), "acres");
    } 
}

var acres = Round(intersectArea,2);

return Text(Round(acres, 2), "#,###.00");

 

I am ultimately trying to just not republish/download the living atlas layers (as to maintain the live and dyanmic updating of the through Esri), but still perform an on the fly calculation and intersection. I would welcome any other suggestions you might have, if this is not achievable via arcade. Open to any AGOL platforms. 

Thanks again for your help!
Sarah 

0 Kudos
ShengdiZhang
Esri Regular Contributor

When adding data via Arcade, the expression needs to return a FeatureSet rather than a single value. Also, since acreage is calculated for each record in the watershed, that calculation should be placed inside the first loop.

However, this approach would require a nested loop. Even with filters applied to both the watershed and states layers, this still results in roughly 5,000 geometry calculations. This can make the initial load of the data very slow, and if network conditions are poor, the request may time out.

I recommend publishing a new dataset with an additional field for the acreage values. That said, if you’d like to try the Arcade method, here’s a sample script for reference:

var p = Portal("https://arcgis.com");
var states = FeatureSetByPortalItem(p, "774019f31f8549c39b5c72f149bbe74e", 0);
var watershed = FeatureSetByPortalItem(p, "42f868d269784624b0a2df9757c34abb", 0);

// Filter states and watershed to New England and New York
states = Filter(states, "STATE_ABBR IN ('ME', 'NH', 'VT', 'MA', 'RI', 'CT', 'NY')")
watershed = Filter(watershed, "states IN ('ME', 'NH', 'VT', 'MA', 'RI', 'CT', 'NY')");

var features = [];

for (var ws in watershed) {
  var intersectArea = 0;

  for (var st in states) {
    intersectArea += AreaGeodetic(Intersection(st, ws), "acres");
  }

  var acres = Round(intersectArea,2);

  Push(features, {
    attributes: {
      HUC10: ws.huc10,
      Acre: acres,
    }
  });
}

// Define schema for output FeatureSet (no geometry, only attributes)
var schema = {
    fields: [{
      name: "HUC10",
      alias: "HUC10",
      type: "esriFieldTypeString"
  }, {
    name: "Acre",
    alias: "Acre",
    type: "esriFieldTypeDouble"
  }],
  geometryType: "",
  features: features
};

return FeatureSet(schema);

You can try to improve performance by only intersecting each watershed record with the matching state polygon.

Thanks,

Shengdi

0 Kudos
SarahHurley1
Occasional Contributor

Thank you so much! This is exactly what I was looking for. 

0 Kudos