Clustering

Global power plants clustered and categorized by fuel type. Clustering summarizes the layer's renderer so you can see the spatial density of features at a glance.

What is clustering?

Clustering is a method of reducing points in a layer by grouping them into clusters based on their spatial proximity to one another. Typically, clusters are proportionally sized based on the number of features within each cluster.

This is an effective way to show areas where many points stack on top of one another.

Clustering allows you to effectively visualize where points stack on top of another or are in very close proximity to each other. Use the swipe widget above to compare an unclustered layer of power plants with a clustered version.

Why is clustering useful?

Large point layers can be deceptive. What appears to be just a few points can in reality be several thousand. Clustering allows you to visually represent large numbers of points in relatively small areas.

For example, the following map shows the locations of thousands of power plants. In the image below, regions A and B both have a high density of points, making them impossible to compare.

clustering disabled

Region A and region B both have a high density of points. It is impossible to tell how many points overlap in each area.

However, when clustering is enabled, the user can now clearly see that region B has nearly twice as many points as region A.

classed with no label

Clustering allows the user to easily compare the density of overlapping features at a glance.

How clustering works

Clustering is configured on the featureReduction property of the layer. You can enable clustering with minimal code by setting the featureReduction type to cluster.

Use dark colors for code blocks
   
1
2
3
layer.featureReduction = {
  type: "cluster"
};

The featureReduction property gives you control over many other cluster properties. The clusterRadius defines each cluster's area of influence for including features. You may also define popupTemplates and labels for clusters to summarize the features included in the cluster.

Examples

Basic clustering

The following example demonstrates how to enable clustering on a point layer and configure labels and a popup for displaying the cluster count.

The aggregate fields used by clusters are generated once clustering is enabled on the layer. By default, all clustered layers have a cluster_count aggregate field. This can be used in the labels and the popup for each cluster. Other fields used in the layer's renderer may be accessible for display in the popup. You can learn more about how to use these in the FeatureReductionCluster.popupTemplate documentation.

See the Related samples and resources below for more examples of how to summarize data within a cluster's popup.

Global power plants clustered by count.
ArcGIS JS API
Use dark colors for code blocks
52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 52 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 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86
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
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <title>Point clustering - basic configuration</title>

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

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

    <script>
      require([
        "esri/WebMap",
        "esri/views/MapView",
        "esri/layers/FeatureLayer"
      ], (
      ) => {
        const clusteredLayer = new FeatureLayer({
          portalItem: {
            id: "eb54b44c65b846cca12914b87b315169"
          renderer: {
            type: "simple",
            symbol: {
              type: "simple-marker",
              size: 6,
              color: "teal",
              outline: {
                color: "white",
                width: 0.5
        clusteredLayer.featureReduction = {
          type: "cluster",
          clusterMinSize: 16.5,
          // defines the label within each cluster
          labelingInfo: [
            {
              deconflictionStrategy: "none",
              labelExpressionInfo: {
                expression: "Text($feature.cluster_count, '#,###')"
              },
              symbol: {
                type: "text",
                color: "white",
                font: {
                  family: "Noto Sans",
                  size: "12px"
                }
              },
              labelPlacement: "center-center"
            }
          ],
          // information to display when the user clicks a cluster
          popupTemplate: {
            title: "Cluster Summary",
            content: "This cluster represents <b>{cluster_count}</b> features.",
            fieldInfos: [{
              fieldName: "cluster_count",
              format: {
                places: 0,
                digitSeparator: true
              }
            }]
          }
        };
        const map = new WebMap({
          basemap: {
            portalItem: {
              id: "75a08e8cd8b64dcfa6945bb7f624ccc5"
          layers: [clusteredLayer]
        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"
          constraints: {
            snapToZoom: false
    </script>
  </head>

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

Suggested cluster defaults

By default, the cluster symbol always summarizes the features in the cluster. When a layer has a UniqueValueRenderer, the symbol of each cluster represents the predominant value of features in the cluster. When a layer has any visual variables applied to it, the average of each variable in the cluster is applied to the cluster symbol. The fields describing the predominant type and average of numeric fields can be referenced in the cluster popup and label.

This example uses smart mapping methods to demonstrate how to generate the suggested cluster configuration specific to the layer's renderer.

Global power plants clustered and categorized by fuel type. Clustering summarizes the layer renderer so you can see a summary of the features contained by the cluster at a glance.
ArcGIS JS API
Use dark colors for code blocks
102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 122 122 122 122 122 122 122 122 122 122 122
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
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <title> Point clustering - unique values</title>

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

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

    <script>
      require([
        "esri/WebMap",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
        "esri/smartMapping/labels/clusters",
        "esri/smartMapping/popup/clusters"
      ], (
      ) => {
        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"
          constraints: {
            snapToZoom: false
          new Expand({
            content: new Legend({ view }),
          "top-left"
          .then( (featureReduction) => {
            // sets generated cluster configuration on the layer
          .catch((error) => {
            console.error(error);
        async function generateClusterConfig(layer) {
          // generates default popupTemplate
          const popupTemplate = await clusterPopupCreator
            .getTemplates({ layer })
            .then( (popupTemplateResponse) => popupTemplateResponse.primaryTemplate.value );

          // generates default labelingInfo
          const { labelingInfo, clusterMinSize } = await clusterLabelCreator
            .getLabelSchemes({
              layer,
              view
            })
            .then((labelSchemes) => labelSchemes.primaryScheme);

          // Set this object on layer.featureReduction
          return {
            type: "cluster",
            popupTemplate,
            labelingInfo,
            clusterMinSize
          };
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>
Image preview of related sample Point clustering - basic configuration

Point clustering - basic configuration

Point clustering - basic configuration

Image preview of related sample Point clustering - generate suggested configuration

Point clustering - generate suggested configuration

Point clustering - generate suggested configuration

Image preview of related sample Point clustering - filter popup features

Point clustering - filter popup features

This sample demonstrates how to filter clustered features within a cluster's popup.

Image preview of related sample Point clustering - query clusters

Point clustering - query clusters

Point clustering - query clusters

Image preview of related sample Point clustering - advanced configuration

Point clustering - advanced configuration

Point clustering - advanced configuration

Image preview of related sample Point clustering with visual variables

Point clustering with visual variables

Point clustering with visual variables

FeatureReductionCluster

Read the API Reference for more information.

API support

The following table describes the geometry and view types that are suited well for each visualization technique.

2D3DPointsLinesPolygonsMeshClient-sideServer-side
Clustering
Heatmap
Opacity
Bloom
Aggregation
Thinning11123
Visible scale range
Full supportPartial supportNo support
  • 1. Feature reduction selection not supported
  • 2. Only by feature reduction selection
  • 3. Only by scale-driven filter

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