FeatureSet

A FeatureSet represents a connection to a set of features in memory or in a server. Similar to an Array, you can iterate through FeatureSets, filter them, and summarize their elements.

Create a FeatureSet

There are three workflows for creating a FeatureSet:

From a FeatureSetCollection

A FeatureSet can be created from a FeatureSetCollection provided as a profile variable. Some profiles, such as Popup and Attribute rules have profile variables that allow you to access data from the parent datastore or other layers in the same context as the profile executing the expression.

For example, in popups, you can create a FeatureSet representing features from another layer in the same map as the feature whose popup was opened by the user. This can be done using one of the following functions:

Use dark colors for code blocksCopy
    
1
2
3
4
// returns the number of sensitive areas that intersect the selected feature
var publicLandFeatures = FeatureSetByName($map, "public lands", ["class"], true);
var sensitiveAreas = Filter(publicLandFeatures, "class = 'sensitive'");
Count( Intersects( sensitiveAreas, $feature ) );

Profiles that support FeatureSet operations may also provide a profile variable, like $layer or $featureSet, which represent the table or layer from with the input feature in the expression originates.

Use dark colors for code blocksCopy
      
1
2
3
4
5
6
// Returns the highest population among all features in the layer
When(
  $feature.Population > ( StdDev($layer, "Population") + Average($layer, "Population") ), "well above average population",
  $feature.Population < ( Average($layer, "Population") - StdDev($layer, "Population") ), "well below average population",
  "normal population"
);

From a portal item

As long as the profile allows you to access data, you can also establish a connection to a FeatureSet from a data source outside the profile's context, such as a layer from ArcGIS Online, or a layer from another portal. This is done with the FeatureSetByPortalItem() function.

Use dark colors for code blocksCopy
    
1
2
3
4
// returns the number of sensitive areas that intersect the selected feature
var p = Portal("https://arcgis.com");
var features = FeatureSetByPortalItem(p, "7b1fb95ab77f40bf8aa09c8b59045449", 0);
Count( Intersects( features, $feature ) );

From scratch

You can also create a FeatureSet completely from scratch using the FeatureSet() function. This is common in the Dashboard data profile, where you can use Arcade to combine data from multiple sources into a single FeatureSet.

Use dark colors for code blocksCopy
                          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var jsonDictionary = {
  fields: [{
    alias: "RANK",
    name: "RANK",
    type: "esriFieldTypeInteger",
  }, {
    alias: "ELEV_m",
    name: "ELEV_m",
    type: "esriFieldTypeInteger",
  }],
  spatialReference: { wkid: 4326 },
  geometryType: "esriGeometryPoint",
  features: [{
    geometry: {
      spatialReference: { wkid: 4326 },
      x: -151.0063,
      y: 63.069,
    },
    attributes: {
      RANK: 1,
      ELEV_m: 6168,
    },
  }]
};

return FeatureSet(Text(jsonDictionary));

In ArcGIS Online, only feature service layers and tables can be referenced in FeatureSet functions. In ArcGIS Pro and ArcGIS Runtime, FeatureSet functions can be used to access data in database tables and feature classes.

Chain FeatureSet operations

FeatureSet functions can be chained, which means that some functions will return a FeatureSet that can be used as input in the next function in the chain. The following expression defines a series of chained operations to find the number of sensitive areas the input feature intersect.

Use dark colors for code blocksCopy
                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// returns the number of sensitive land features that intersect the feature displaying the popup
Count(
  Intersects(
    Buffer(
      Filter(
        FeatureSetByName(
          $map, "public lands", ["class"], true
        ),
        "class = 'sensitive'"
      ),
      10,
      "square-kilometers",
    ),
    $feature
  )
);

The following describes the order of operations in the chain:

  1. FeatureSetByName defines the layer or table to query. It is used as input to...
  2. Filter which defines the filter. Only sensitive lands are returned and provided as input to...
  3. Buffer which defines the area to use in a spatial filter. This is used as input to...
  4. Intersects which defines the spatial operation to use in the geometry filter. The intersecting sensitive lands are provided as input to...
  5. Count which returns the count of features that satisfy the query.

A FeatureSet function will not trigger a request to the server until the result is required for another statement or returned in the expression. In this example, all the functions in this chain can be used to build one network request.

Once a FeatureSet is available on the client, all FeatureSet operations performed on the result will be executed client-side, thus avoiding more network requests. In web maps, you cannot force the expression to make client-side queries to layers visible in your view.

Performance

Chaining is useful because it allows the script to make a single server request, thus maximizing the performance of the script. However, script performance largely depends on how it is written. For example, you can iterate through FeatureSets using a for loop.

Use dark colors for code blocksCopy
      
1
2
3
4
5
6
var totalArea = 0;
// loops through every feature in the layer
for(var f in $layer){
  totalArea += AreaGeodetic(f, "square-kilometers");
}
return totalArea;

In this expression, all features must be downloaded to the client. This may be acceptable for small layers, but for layers with a lot of features and/or many attributes, this can significantly slow down the performance of the expression.

We advise avoiding iteration through FeatureSets when possible. If you must iterate through features, try to filter the FeatureSet to only a few features, such as the top five.

Use dark colors for code blocksCopy
         
1
2
3
4
5
6
7
8
9
var topFive = Top( OrderBy( $layer, 'POPULATION DESC' ), 5 );
var list = "<ol>";

for (var f in topFive){
  var diff = Text((f.POPULATION - $feature.POPULATION) / f.POPULATION, "#.#%");
  list += `<li>${f.Name} - ${f.POPULATION} (${diff})</li>`;
}
list += "</ol>";
return list;

This will only require the script to download a subset of features to the client.

Exclusive profiles

FeatureSets are excluded in profiles that execute Arcade for all features rendered in a view, such as visualization and labeling. Blocking FeatureSet functions in these profiles prevents excessive network requests and database queries that would hinder app performance.

Let's compare the Popup profile, where FeatureSets are allowed, to the Visualization profile, where they are blocked.

FeatureSets in popups

When the user clicks a feature in a map to open its popup, all Arcade expressions required for the popup content to render execute only once. These expressions may use FeatureSets to access data from other layers. That means that for every click to open a popup containing an Arcade expression that accesses data from another layer, the expression's execution context will make at least one network request for that data.

Depending on the complexity of the request, the size of the response, network connectivity, and server latency, the client may wait anywhere from a few milliseconds to several seconds to get a response from the server.

FeatureSets in visualization

In the case of a popup, the time to wait for the data to load and content to render in the popup may be acceptable. However, it will not work in a profile like Visualization where one expression may be executed hundreds of thousands of times for the visualization to take effect. Making 100,000 network requests could overload the server, freeze the app, and ultimately frustrate the end user.

The following expression will execute at least one network request each time the expression executes. If allowed in a visualization context, it would attempt to make the request for every feature in the layer.

Use dark colors for code blocksCopy
               
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Count(
  Intersects(
    Buffer(
      Filter(
        FeatureSetByName(
          $map, "public lands", ["class"], true
        ),
        "class = 'sensitive'"
      ),
      10,
      "square-kilometers",
    ),
    $feature
  )
);

If you require data from another source for use in a visualization of a layer you own, you can calculate a new field, and use FeatureSet functions in the calculation expression.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.