Point clustering - filter popup features

Explore in the sandboxView live

This sample demonstrates how to query and filter features represented by point clusters using Arcade expressions in a cluster's popup.

Typically clusters display basic summary information about all features in the cluster, such as the total number of features, the predominant type, or the average value of a numeric field. Sometimes you may want to display information about a subset of important features, such as the number of fatalities in a cluster representing car crashes.

The cluster popup in this example displays the total number of power plants that generate power with coal, along with the amount of power they produce as a ratio to all power produced in the cluster. This is all accomplished with Arcade expressions. Within the context of a cluster popup, you can use Arcade to filter a cluster's features and perform statistics on those features.

Use Arcade to summarize clusters

Arcade expressions in cluster popups give you access to the cluster graphic itself (i.e. $feature) and the features that make up the cluster (i.e. $aggregatedFeatures).

$feature

The $feature global allows you to reference aggregate fields used by the renderer, such as $feature.cluster_count. If the renderer visualizes population with a numeric POP field, you will have access to the average population of features in the cluster by referencing $feature.cluster_avg_POP within the expression.

$aggregatedFeatures

The $aggregatedFeatures global represents all features included in the cluster. You can use this global to iterate through features, filter them, and calculate statistics with the features.

   
1
2
3
// returns the total number of features in the cluster
// this will be the same as $feature.cluster_count
Count($aggregatedFeatures)
  
1
2
// returns the count of features of fuel type 'Coal' within the cluster
Count(Filter($aggregatedFeatures, "fuel1 = 'Coal'"))

The Expects Arcade function tells the clustered layer to request extra fields required for the popup to function properly.

                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// returns the amount of power generated by coal power plants
// as a percentage of total power produced in the cluster along
// with the total number of coal power plants

// Since the capacity_mw field may not be available on the client
// at runtime, we tell the Arcade engine to request it from the layer
Expects($aggregatedFeatures, "capacity_mw")
var mWtotal = Sum($aggregatedFeatures, "capacity_mw");
var mWCoal = Sum(Filter($aggregatedFeatures, "fuel1 = 'Coal'"), "capacity_mw");
if(mWCoal < 1){
  return "none";
}
var mWratio = Round(mWCoal / mWtotal, 4);
return \`\${Text(mWratio, "#.#%")} (\${Text(mWCoal, "#,### mW")})\`;

// the output will look like "15% (6,500 mW)"

To use values returned from Arcade expressions within a popup, you must set the Arcade expressions in the expressionInfos property of the popupTemplate, then reference it using the {expression/expression-name} syntax.

Calculate cluster statistics
107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135 135
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />

    <title>Point clustering - filter popup features | Sample | ArcGIS API for JavaScript 4.21</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.21/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.21/"></script>

    <style>
      html,
      body,
      #viewDiv {
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
    </style>

    <script>
      require([
        "esri/WebMap",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
        "esri/smartMapping/labels/clusters"
      ], function (
      ) {
        const layer = new FeatureLayer({
          portalItem: {
            id: "eb54b44c65b846cca12914b87b315169"
        const map = new WebMap({
          basemap: {
            portalItem: {
              id: "75a08e8cd8b64dcfa6945bb7f624ccc5"
          layers: [layer]
        const view = new MapView({
          container: "viewDiv",
          extent: {
            spatialReference: {
              latestWkid: 3857,
              wkid: 102100
            xmin: -15327459,
            ymin: 2740044,
            xmax: -6076744,
            ymax: 6878650
          popup: {
            dockEnabled: true,
            dockOptions: {
              breakpoint: false,
              position: "top-right"
          new Expand({
            content: new Legend({ view }),
          "top-left"
          .then(async (featureReduction) => {
            // sets generated cluster configuration on the layer
            // Disable clustering when user zooms beyond a 1:50,000 scale level
            // Re-enable clustering when the user zooms out to a scale smaller than 1:50,000
            view.watch("scale", function (scale) {
                view.scale > 50000 ? featureReduction : null;
          .catch((error) => {
            console.error(error);
        async function generateClusterConfig(layer) {
          let popupTemplate = {
            title: "Coal summary",
            content: `<p>This cluster represents <b>{cluster_count}</b> power plants. <b>{expression/Coal-count}</b> of these plants are fueled by Coal.</p><p>Coal plants produce <b>{expression/Coal-mw-sum}</b> of the total power generated in this cluster.</p>`,
            expressionInfos: [{
              name: "Coal-count",
              title: "Coal-count",
              expression: `
                // returns the total number of coal power plants
                Count(Filter($aggregatedFeatures, "fuel1 = 'Coal'"))
              `
            }, {
              name: "Coal-mw-sum",
              title: "Coal-mw-sum",
              expression: `
                // returns the amount of electricity generated by coal
                // in this cluster as a ratio to the total capacity
                // of plants included in the cluster
                Expects($aggregatedFeatures, "capacity_mw")
                var mWtotal = Sum($aggregatedFeatures, "capacity_mw");
                var mWCoal = Sum(Filter($aggregatedFeatures, "fuel1 = 'Coal'"), "capacity_mw");
                if(mWCoal < 1){
                  return "none";
                }
                var mWratio = Round(mWCoal / mWtotal, 4);
                return \`\${Text(mWratio, "#.#%")} (\${Text(mWCoal, "#,### mW")})\`;
              `
            }]
          };
          // generates default labelingInfo
          const { labelingInfo, clusterMinSize } = await clusterLabelCreator
            .then((labelSchemes) => labelSchemes.primaryScheme);
          return {
            type: "cluster",
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>

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