Display clusters

Clustering groups points into clusters based on their spatial proximity to one another. Clusters can reveal information that is difficult to visualize when there are hundreds or thousands of points in a map that may overlap or cover each other. Adopt clustering if you want to discover patterns in your data, such as:

  • Identify where students live in a city so that the local government can plan appropriate educational and accommodation resources. Clustering allows you to visualize this data without revealing the individual student addresses.
  • Visualize the most common type of environmental complaints that are registered across a city so that authorities can plan how to deploy their environmental officers.
  • Ensure that police units are evenly spread throughout city so that a rapid response time can be maintained for emergency calls from the public.

In the map below, for example, various power plants of north-west Europe are clustered together so that you can easily see the count of power plants in each region. The size of each cluster is proportional to the number of points in each cluster and is recalculated when the map is zoomed.

Clustering

Clustering can be defined on a point feature layer authored and published using the ArcGIS Online Map Viewer or ArcGIS Pro. If you add a feature layer from an ArcGIS feature service, web map, or mobile map package to your app, any predefined clustering displays automatically.

If the published point feature layer is not enabled with clustering, or if you want to cluster point graphics, you can use this SDK to define clustering by following the steps detailed in Enable clustering. You can enhance the visual representation of the clusters and display summary statistics of the clustered point attributes (not just the number of points) by using a variety of more complex renderers, labels, and popups, as described in Enhanced statistics and renderers.

Enable clustering

To cluster point-based features or graphics in your app, you need to create a ClusteringFeatureReduction object that takes a renderer. The renderer determines the cluster's color and shape, but the cluster's size is determined by the number of points in the cluster. So, a cluster with more points is bigger than a cluster with fewer points. You can cluster point features or graphics as follows:

  1. Create a SimpleRenderer using a SimpleMarkerSymbol.
  2. Create a ClusteringFeatureReduction using the simple renderer.
  3. Pass the ClusteringFeatureReduction to the FeatureLayer.featureReduction or the GraphicsOverlay.featureReduction.
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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        val simpleMarkerSymbol = SimpleMarkerSymbol(color = Color.cyan)
        val simpleRenderer = SimpleRenderer(symbol = simpleMarkerSymbol)
        val clusteringFeatureReduction = ClusteringFeatureReduction(renderer = simpleRenderer)
        featureLayer.featureReduction = clusteringFeatureReduction
        // Alternatively, set the feature reduction on the graphics overlay.
        graphicsOverlay.featureReduction = clusteringFeatureReduction

The map below contains a single point symbol for the 8000+ power plants in the United States. On the right side, the points are aggregated into clusters using the default clustering values. Every time the mapview's viewpoint changes the clusters may be recalculated and their symbols redrawn.

Clustering.

Label clusters

The number of points in the cluster is stored in a field called "cluster_count" and is updated every time the cluster redraws. You can display this information in the clusters label, as follows:

  1. Create a LabelDefinition that uses a SimpleLabelExpression of "[cluster_count]" and a black TextSymbol.
  2. Set label definition placement.
  3. Add the label definition to the ClusteringFeatureReduction.
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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        // Create a label definition with a simple label expression.
        val simpleLabelExpression = SimpleLabelExpression(simpleExpression = "[cluster_count]")
        val textSymbol = TextSymbol(
            text = "",
            color = Color.black,
            size = 12.0f,
            horizontalAlignment = HorizontalAlignment.Center,
            verticalAlignment = VerticalAlignment.Middle
        )
        val labelDefinition = LabelDefinition(
            labelExpression = simpleLabelExpression,
            textSymbol = textSymbol
        ).apply {
            placement = LabelingPlacement.PointCenterCenter
        }
        // Add the label definition to the feature reduction.
        clusteringFeatureReduction.labelDefinitions.add(labelDefinition)

The map below shows clusters labeled with a SimpleLabelExpression.

Clustering.

Configure clusters

The process of clustering groups points into clusters based on an area of influence defined in screen space by the ClusteringFeatureReduction.radius. This radius has a default value which is 60 device-independent pixels (dpi), but you can set it to a higher value to aggregate points from a larger area or to a lower value to aggregate points from a smaller area. The size of each cluster symbol on the map is proportional to the number of features within the cluster and is recalculated every time the viewpoint changes.

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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        clusterRadius = clusterRadiusOptions[index]
        clusteringFeatureReduction.radius = clusterRadius.toDouble()

The map below shows points clustered with a clustering radius of 120.

Clustering.

Enhanced statistics and renderers

You can enhance the information displayed to your users by presenting statistical information, such as the average, max, and mode value of the cluster's point attributes. First, you need to aggregate, or summarize, the cluster's point data, and then you can:

  • Apply advanced renderers, such as class break and unique value renderers.
  • Configure labels that use simple or Arcade expressions.
  • Design user friendly popup text.

Aggregate the point data

First, examine the attributes in your feature layer or graphics overlay and decide which attributes you want to summarize. Next, specify how the attribute values are summarized and store the results in an aggregate field, as follows:

  1. Create a new AggregateField for each statistical operation you want to perform on an attribute. Give it a name.
  2. Set the statisticFieldName as the attribute (from the feature layer or graphic overlay) you want to analyze.
  3. State the AggregateStatisticType, such as count, average, mode, and max, that will be applied to the statisticFieldName.
  4. Add a collection of your aggregate fields to your ClusteringFeatureReduction so they can be used by its renderer, label, and popup definitions.

The code below creates and adds 3 AggregateField objects to the ClusteringFeatureReduction. In the first one, for example, the value of the "fuel1" field that appears most often (mode value) is stored in the "most_common_fuel" aggregate field, the average value of the "capacity_mw" field is stored in the "average_capacity_mw" aggregate field and so on.

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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        // Create a new clustering feature reduction using the class breaks renderer.
        return ClusteringFeatureReduction(classBreaksRenderer).apply {
            // Set the feature reduction's aggregate fields. Note that the field names must match the names of fields in the feature layer's dataset.
            // The aggregate fields summarize values based on the defined aggregate statistic type.
            aggregateFields.add(
                AggregateField(
                    name = "most_common_fuel",
                    statisticFieldName = "fuel1",
                    statisticType = AggregateStatisticType.Mode
                )
            )
            aggregateFields.add(
                AggregateField(
                    name = "average_capacity_mw",
                    statisticFieldName = "capacity_mw",
                    statisticType = AggregateStatisticType.Average
                )
            )
            aggregateFields.add(
                AggregateField(
                    name = "total_capacity_mw",
                    statisticFieldName = "capacity_mw",
                    statisticType = AggregateStatisticType.Sum
                )
            )

Apply a class breaks renderer

You can apply a renderer to the cluster to display the value of the aggregate fields. Class breaks renderers are useful if you want to apply different colors to ranges of values. You can apply a class breaks renderer to the cluster as follows:

  1. For each range of values, create a ClassBreak and assign a SimpleMarkerSymbol with a unique color.
  2. Create a ClassBreaksRenderer for the aggregate field and provide the collection of class breaks.
  3. Pass the class breaks renderer to the constructor of the ClusteringFeatureReduction and pass that to FeatureLayer.featureReduction or GraphicsOverlay.featureReduction.
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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        // Create a class breaks renderer to apply to the custom feature reduction.
        val classBreaksRenderer = ClassBreaksRenderer().apply {
            // Define the field to use for the class breaks renderer.
            // Note that this field name must match the name of an aggregate field contained in the clustering feature reduction's aggregate fields property.
            fieldName = "total_capacity_mw"

            // Add a class break for each intended value range and define a symbol to display for features in that range.
            val classBreak1 = ClassBreak(
                description = "<5000",
                label = "<5000",
                minValue = 0.0,
                maxValue = 5000.0,
                symbol = SimpleMarkerSymbol(color = Color.cyan),
                alternateSymbols = listOf(
                    SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 192, b = 203))
                )
            )
            val classBreak2 = ClassBreak(
                description = ">5000",
                label = ">5000",
                minValue = 5001.0,
                maxValue = 10000.0,
                symbol = SimpleMarkerSymbol(color = Color.fromRgba(r = 62, g = 180, b = 137)),
                alternateSymbols = listOf(SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 192, b = 203)))
            )
            val classBreak3 = ClassBreak(
                description = ">10000",
                label = ">10000",
                minValue = 10001.0,
                maxValue = 15000.0,
                symbol = SimpleMarkerSymbol(color = Color.green),
                alternateSymbols = listOf(SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 192, b = 203)))
            )
            val classBreak4 = ClassBreak(
                description = ">15000",
                label = ">15000",
                minValue = 15001.0,
                maxValue = 50000.0,
                symbol = SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 165, b = 0)),
                alternateSymbols = listOf(SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 192, b = 203)))
            )
            val classBreak5 = ClassBreak(
                description = ">50000",
                label = ">50000",
                minValue = 50001.0,
                maxValue = 1000000.0,
                symbol = SimpleMarkerSymbol(color = Color.red),
                alternateSymbols = listOf(SimpleMarkerSymbol(color = Color.fromRgba(r = 255, g = 192, b = 203)))
            )

            classBreaks.addAll(listOf(classBreak1, classBreak2, classBreak3, classBreak4, classBreak5))
            // Define a default symbol to use for features that do not fall within any of the ranges defined by the class breaks.
            defaultSymbol = SimpleMarkerSymbol().apply { color = Color.red }
        }

The map below shows the clusters rendered with a class breaks renderer and reflects the range of total_capacity_mw values. For example, the red color indicates that the sum of the capacity_mw of all the points in a cluster is greater than 50000 MW.

Clustering.

Configure label expressions

As shown previously, you can label each cluster with the number of points in the cluster. However, now that you have created some aggregate fields, you can use these to label the clusters by configuring a SimpleLabelExpression or an ArcadeLabelExpression.

In the map below, the most_common_fuel aggregate field value of each cluster is displayed in a label by using a SimpleLabelExpression. For more information about how to format simple expression strings, see Simple expressions.

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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        val classBreaksRenderer = ClassBreaksRenderer()
        val clusteringFeatureReduction = ClusteringFeatureReduction(renderer = classBreaksRenderer)
        val commonFuelLabelExpression =
            SimpleLabelExpression(simpleExpression = "[most_common_fuel]")
Clustering.

In the map below, the total_capacity_mw aggregate field value of each cluster is reformated, concatenated with the "MW", and displayed in a label by using an ArcadeLabelExpression. For more information about how to format Arcade expression strings, see Arcade expressions.

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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        val labelExpression =
            ArcadeLabelExpression(arcadeString = "Concatenate([Text(\$feature.total_capacity_mw, '###,###') + ' MW'])")
Clustering.

Configure popup expressions

You can configure your app to display a popup when the user clicks on a cluster. By default, the cluster's popup displays its "point_count" value; the number of points in the cluster. If the ClusteringFeatureReduction has aggregate fields, the cluster popup will display the aggregate field values. However, if you want to present a more user-friendly text, you can create an Arcade expression, as follows:

  1. Create a PopupDefinition using the ClusteringFeatureReduction.
  2. Assign the popup definition to the clustering feature reduction.
  3. Specify a title and remove all elements from the popup definition.
  4. Create a PopupExpression, provide an Arcade expression, and specify that the return type is string. In this example, the Arcade expression reformats and concatenates a few aggregate fields representing the average and total capacities, along with some helpful text.
  5. Create an ExpressionPopupElement using the popup expression.
  6. Add the expression popup element to the popup definition's collection of elements.
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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        // Set the popup definition for the custom feature reduction.
        clusteringFeatureReduction.popupDefinition = PopupDefinition(clusteringFeatureReduction).apply {
            this.title = "Cluster summary"
            this.elements.clear()
        }

        val popupExpression1 = PopupExpression().apply {
            expression = "var result = Concatenate(['The power plants in this cluster have an average capacity of ' +" +
                    "Text(\$feature.average_capacity_mw, '#.00') + ' megawatts and produce a total of ' +" +
                    "Text(\$feature.total_capacity_mw, '###,###.00') + ' megawatts of power.']);" +
                    "return { type : 'text', text : result };"
            returnType = PopupExpressionReturnType.String
        }

        val expressionPopupElement1 = ExpressionPopupElement(popupExpression = popupExpression1)

        // Optionally, create additional popup expressions.
        val popupExpression2 = PopupExpression().apply {
            expression = "var result = Concatenate(['Most power plants in this cluster generate power from ' + " +
                    "\$feature.most_common_fuel + '.']);" +
                    "return { type : 'text', text : result };"
        }

        val expressionPopupElement2 = ExpressionPopupElement(popupExpression = popupExpression2)

        clusteringFeatureReduction.popupDefinition?.elements?.addAll(listOf(expressionPopupElement1, expressionPopupElement2))

For more information about how to add popups to your app, see the PopupView component and example code that is provided by the ArcGIS Maps SDK for Kotlin Toolkit

The map below shows a popup configured with a PopupExpression.

Clustering.

Samples

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