Scale-aware visualizations

Census tracts styled with a dot density renderer to show population density by race and ethnicity

Why does view scale matter?

Web maps often span multiple scale levels. This makes styling layers complicated. For example, you may define icon sizes that work well at one scale, but zooming in or out could quickly turn your good cartographic decisions into mediocre ones.

In fact, one icon size usually doesn’t look good at all scales. This is especially true for dense layers. For example, the points in the map below look good with a size of 10px at a national scale.

10px icons at larger scales
Figure A: At this scale, points are appropriately sized at 10px.

But when zoomed out to a worldwide extent, 10px appears too big in the dense areas. The large icon size obscures the underlying data, potentially misrepresenting its density.

10px icons at a worldwide scale
Figure B: At this scale, 10px points are too large.

With a smaller point symbol, many of the issues listed above can be reduced or eliminated.

3px icons at a world scale
Figure C: At this scale, 3px points look better.

However, the 3px size makes the points almost impossible to see when you zoom back to regional scales or beyond.

3px icons at a national scale
Figure D: At this scale, 3px points are difficult to see.

Scale-dependent properties

Because icon sizes, line widths, and densities don't display well at all scales, the ArcGIS JS API allows you to configure various symbol and renderer properties based on view scale.

The following symbol and renderer properties can be adjusted according to the view scale.

  1. Symbol sizes
  2. Polygon outline widths
  3. Data-driven size ranges (i.e. graduated symbols)
  4. Dot density values

Symbol sizes

You can dynamically change point sizes and line widths to work well at any scale using a size visual variable. You must add an Arcade expression that returns the view scale to the size variable (e.g. $view.scale). Then you can map specific scale values to sizes in the stops property. All other scale levels will interpolate the size linearly.

The following snippet treats the view scale as if it were a data value. The raw scale value is returned, and the values in the size stops correspond to scale levels. The renderer will display point sizes (or line widths) at the sizes indicated for each scale in the stops.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
renderer.visualVariables = [
  {
    type: "size",
    valueExpression: "$view.scale",
    stops: [
      // view scales larger than 1:1,155,581
      // will have a symbol size of 7.5 pts
      { size: 7.5, value: 1155581 },
      { size: 6, value: 9244648 },
      { size: 3, value: 73957190 },
      // view scales smaller than 1:591,657,527
      // will have a symbol size of 1.5 pts
      { size: 1.5, value: 591657527 }
    ]
  }
];

Example

The following example demonstrates how to adjust the size of points by view scale. This size variable can be used for any point or polyline visualization regardless of renderer type (as long as it supports visual variables).

Use the Disable/enable auto size by scale button to explore how not adjusting icon sizes by scale affects the visualization at various scale levels.

Vary icon size by scale
Expand
Use dark colors for code blocksCopy
49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 49 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 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78
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

        const sizeVV = {
          type: "size",

          valueExpression: "$view.scale",

          stops: [
            { size: 9, value: 1155581 },
            { size: 6, value: 9244648 },
            { size: 3, value: 73957190 },
            { size: 1.5, value: 591657527 }
          ]
        };


        const renderer = new SimpleRenderer({
          symbol: {
            type: "simple-marker",
            color: "dodgerblue",
            outline: {
              color: [255, 255, 255, 0.7],
              width: 0.5
            },
            size: "3px"
          },

          visualVariables: [sizeVV]

        });
Expand

Polygon outlines

Overly thick outlines can hide small features and distract from the purpose of a visualization. Because of this, many people instinctively remove outlines. However, this practice can be problematic.

For example, the image below shows outlines that are so thick they completely obscure the fill color of small polygons in the downtown Houston area.

Large outlines zoomed out
Figure E: At this scale, thick outlines obscure a significant number of features, making the visual difficult to interpret.

That outline width is clearly unacceptable. But if you zoom to a very large scale, that outline choice may actually work well.

Large outlines zoomed in
Figure F: At this scale, thick outlines don't distract from the visualization or obscure features.

Removing outlines at large scales makes it impossible to see the boundaries of neighboring features with the same color.

side-by-side zoomed in outlines
Figure G: The figure on the left shows that removing outlines makes it impossible to see the boundaries of similar features. The figure on the right shows that adding outlines makes these boundaries clear.

Similar to adjusting symbol sizes by scale, you can adjust polygon outline widths using a size visual variable with a $view.scale Arcade expression. This scenario requires setting the target property to outline so the renderer knows to apply the size variable to the symbol outline.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
renderer.visualVariables = [
  {
    type: "size",
    valueExpression: "$view.scale",
    target: "outline",
    stops: [
      { size: 2, value: 56187 },
      { size: 1, value: 175583 },
      { size: 0.5, value: 702332 },
      { size: 0, value: 1404664 }
    ]
  }
];

Example

The following example demonstrates how to adjust the outline of polygons by view scale. Zoom in to observe the thickening of the outlines. Zoom out to see the outlines get thinner and eventually disappear.

Vary outline width by scale
Expand
Use dark colors for code blocksCopy
95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 96 97 98 99 100 101 102 103 104 105 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106 106
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
        renderer.visualVariables = [ {
          type: "size",
          valueExpression: "$view.scale",
          target: "outline",
          stops: [
            { size: 2, value: 56187 },
            { size: 1, value: 175583 },
            { size: 0.5, value: 702332 },
            { size: 0, value: 1404664 }
          ]
        }];
Expand

Data-driven size ranges

You can also optimize visualizations of data-driven continuous size (i.e. graduated symbols) by scale. This will cause the entire range of symbols to grow in size as you zoom in, and shrink as you zoom out. When creating a continuous size visualization, you set a minSize and maxSize that correspond to a minDataValue and a maxDataValue.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
renderer.visualVariables = [{
  type: "size",
  field: "Population",
  minDataValue: 1,
  maxDataValue: 1000000,
  maxSize: 40,
  minSize: 4
}]

You can adjust the range of all symbol sizes by scale even though they vary depending on a data value. In this scenario you must set a scale-dependent size variable to both the maxSize and minSize properties. See the example below.

Example

The following example demonstrates how to adjust symbol sizes that vary based on a data value by view scale.

Size range by scale
Expand
Use dark colors for code blocksCopy
98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 98 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 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127
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
            visualVariables: [{
              type: "size",
              valueExpression: sizeValueExpression,
              valueExpressionTitle: "Shift in percentage points",
              minDataValue: 0,
              maxDataValue: 30,

              maxSize: {
                type: "size",
                valueExpression: "$view.scale",
                stops: [
                  { size: 42, value: 288895 },
                  { size: 38.6, value: 2311162 },
                  { size: 24, value: 18489297 },
                  { size: 11, value: 147914381 }
                ]
              },
              minSize: {
                type: "size",
                valueExpression: "$view.scale",
                stops: [
                  { size: 8, value: 288895 },
                  { size: 4, value: 2311162 },
                  { size: 1, value: 18489297 },
                  { size: 0.4, value: 147914381 }
                ]
              }

            }]
Expand

Dot density values

Dot density visualizations are sensitive to view scale. At a constant dot value, the density of features will appear inconsistent as the user zooms in and out. The DotDensityRenderer allows you to linearly scale the dot value based on the view scale. This is configured with the referenceScale property. As you zoom in and out of the initial view, the relative density of points remains the same across scales.

In addition to setting a referenceScale, you should typically set a minScale on the layer. Dot density visualizations are difficult to read when dots are no longer distinguishable, either because they coalesce or because they are too dispersed.

Setting a maxScale on the layer is also important because dot density maps tend to become unreadable at larger scales. Users may start seeing patterns in the random distribution of dots that do not exist in reality. They may also mistakenly interpret the location of each dot as an actual point feature. Users are particularly susceptible to this when the dotValue is set to 1. As an example, dot density visualizations on county datasets should only be viewed at the state or regional level.

Example

The example below visualizes the density of the population by race in the United States. At a scale of 1:577,790, each dot represents 100 people. That dotValue will automatically adjust as the user zooms in and out. You can note this change in the legend.

ArcGIS JS API
Expand
Use dark colors for code blocksCopy
75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 76 77 78 79 80 81 82 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83 83
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
          const dotDensityRenderer = new DotDensityRenderer({
            dotValue: 100,
            outline: null,
            referenceScale: 577790, // 1:577,790 view scale
            legendOptions: {
              unit: "people"
            }
          });
Expand
Image preview of related sample Vary point sizes by scale

Vary point sizes by scale

Vary point sizes by scale

Image preview of related sample Create a scale-dependent visualization

Create a scale-dependent visualization

Create a scale-dependent visualization

Image preview of related sample Dot density

Dot density

Dot density

Image preview of related sample Generate a dot density visualization

Generate a dot density visualization

Generate a dot density visualization

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