Arcade-driven visualizations

U.S. counties styled with a UniqueValueRenderer showing the predominant political party affiliation of registered voters.

What is Arcade?

Sometimes you need to render an attribute that doesn't exist in your layer. Arcade is an expression language that allows you to calculate values for each feature in a layer at runtime and use those values as the basis for a data-driven visualization. This is convenient when you need to derive new data values on data sources that update frequently, or on layers that you don't own.

See the Arcade - expression language guide for more details about how to use Arcade in other parts of the ArcGIS API for JavaScript.

How Arcade works

Arcade expressions are referenced as strings in the valueExpression property of ClassBreaksRenderer, UniqueValueRenderer, DotDensityRenderer or any visual variable: color, size, opacity, and rotation. When defined, it is always used instead of referencing a field/normalizationField.

When used in a ClassBreaksRenderer, DotDensityRenderer, or any of the visual variables, the value expression must evaluate to a number. Expressions may evaluate to either strings or numbers in UniqueValueRenderer.

Examples

Predominance with UniqueValueRenderer

In this example, Arcade is used to create a predominance map showing the most common political party affiliation in each U.S. county. The underlying layer has three fields that identify the number of republicans, democrats, and independent/non-party voters in each county. Since the service does not contain a field indicating the predominant party, we can write an Arcade expression to identify that for each feature.

The Arcade expression is referenced in the valueExpression property of a UniqueValueRenderer.

Predominance Arcade expression
38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <title>Create a custom visualization using Arcade</title>

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

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

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        Map,
      ) {
        const renderer = {
          type: "unique-value",
          valueExpression: `
            // store field values in variables with
            // meaningful names. Each is the total count
            // of votes for the respective party

            var republican = $feature.MP06025a_B;
            var democrat = $feature.MP06024a_B;
            var independent = $feature.MP06026a_B;
            var parties = [republican, democrat, independent];

            // Match the maximum value with the label
            // of the respective field and return it for
            // use in a UniqueValueRenderer

            return Decode( Max(parties),
              republican, 'republican',
              democrat, 'democrat',
              independent, 'independent',
            'n/a' );
          `,
          valueExpressionTitle: "Counties by dominant party among registered voters",
          uniqueValueInfos: [
              value: "democrat",
              symbol: createSymbol("#00c3ff"),
              label: "Democrat"
              value: "republican",
              symbol: createSymbol("#ff002e"),
              label: "Republican"
              value: "independent",
              symbol: createSymbol("#faff00"),
              label: "Independent/other party"
        const layer = new FeatureLayer({
          portalItem: {
            id: "8444e275037549c1acab02d2626daaee"
          popupTemplate: {
            title: "{COUNTY}, {STATE}",
            content: [
                type: "fields",
                fieldInfos: [
                    fieldName: "MP06024a_B",
                    label: "Democrat",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06025a_B",
                    label: "Republican",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06026a_B",
                    label: "Independent/Other",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "POP18UP_CY",
                    label: "Adult Population",
                    format: {
                      digitSeparator: true,
                      places: 0
        const map = new Map({
          basemap: "dark-gray-vector",
          layers: [layer]
        const view = new MapView({
          container: "viewDiv",
          map: map,
          center: [-95, 38],
          zoom: 4
        const legend = new Legend({
          view: view,
          layerInfos: [
              layer: layer,
              title: "Dominant political party by number of registered voters for each U.S. County"
        view.ui.add(new Expand({
          content: legend
        }), "top-right");
        // Creates a SimpleFillSymbol based on an input color
        function createSymbol(color) {
          return {
            type: "simple-fill", // autocasts as new SimpleFillSymbol()
            color: color,
            outline: {
              width: 0.2,
              color: [0, 0, 0, 0.1]
    </script>
  </head>

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

Then assign unique symbols for each expected return value in the renderer.

Unique value infos
63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <title>Create a custom visualization using Arcade</title>

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

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

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        Map,
      ) {
        const renderer = {
          type: "unique-value",
          valueExpression: `
          `,
          valueExpressionTitle: "Counties by dominant party among registered voters",
          uniqueValueInfos: [
            {
              value: "democrat",
              symbol: createSymbol("#00c3ff"),
              label: "Democrat"
            },
            {
              value: "republican",
              symbol: createSymbol("#ff002e"),
              label: "Republican"
            },
            {
              value: "independent",
              symbol: createSymbol("#faff00"),
              label: "Independent/other party"
            }
          ]
        const layer = new FeatureLayer({
          portalItem: {
            id: "8444e275037549c1acab02d2626daaee"
          popupTemplate: {
            title: "{COUNTY}, {STATE}",
            content: [
                type: "fields",
                fieldInfos: [
                    fieldName: "MP06024a_B",
                    label: "Democrat",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06025a_B",
                    label: "Republican",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06026a_B",
                    label: "Independent/Other",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "POP18UP_CY",
                    label: "Adult Population",
                    format: {
                      digitSeparator: true,
                      places: 0
        const map = new Map({
          basemap: "dark-gray-vector",
          layers: [layer]
        const view = new MapView({
          container: "viewDiv",
          map: map,
          center: [-95, 38],
          zoom: 4
        const legend = new Legend({
          view: view,
          layerInfos: [
              layer: layer,
              title: "Dominant political party by number of registered voters for each U.S. County"
        view.ui.add(new Expand({
          content: legend
        }), "top-right");
        // Creates a SimpleFillSymbol based on an input color
        function createSymbol(color) {
          return {
            type: "simple-fill", // autocasts as new SimpleFillSymbol()
            color: color,
            outline: {
              width: 0.2,
              color: [0, 0, 0, 0.1]
    </script>
  </head>

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

Arcade-driven opacity

Arcade can be used anywhere a data value is referenced in a renderer, including visual variables. The following snippet references an Arcade expression in an opacity visual variable to calculate the percentage of voters comprising the predominant party in each county. The opacity stops map the expected data values to opacity values.

Opaque counties indicate areas where the predominant political party comprises the vast majority of voters. Transparent counties show areas where there is a more diverse mix of individuals belonging to each political party.

ArcGIS JS API
84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 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
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

    <title>Create a custom visualization using Arcade</title>

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

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

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        Map,
      ) {
        const renderer = {
          type: "unique-value",
          valueExpression: `
          `,
          valueExpressionTitle: "Counties by dominant party among registered voters",
          uniqueValueInfos: [
              value: "democrat",
              symbol: createSymbol("#00c3ff"),
              label: "Democrat"
              value: "republican",
              symbol: createSymbol("#ff002e"),
              label: "Republican"
              value: "independent",
              symbol: createSymbol("#faff00"),
              label: "Independent/other party"
        renderer.visualVariables = [{
          type: "opacity",
          valueExpression: `
            var republican = $feature.MP06025a_B;
            var democrat = $feature.MP06024a_B;
            var independent = $feature.MP06026a_B;
            var parties = [republican, democrat, independent];
            var total = Sum(parties);
            var max = Max(parties);

            return (max / total) * 100;
          `,
          valueExpressionTitle: "Share of registered voters comprising the dominant party",
          stops: [
            { value: 33, opacity: 0.05, label: "< 33%" },
            { value: 44, opacity: 1.0, label: "> 44%" }
          ]
        }];
        const layer = new FeatureLayer({
          portalItem: {
            id: "8444e275037549c1acab02d2626daaee"
          popupTemplate: {
            title: "{COUNTY}, {STATE}",
            content: [
                type: "fields",
                fieldInfos: [
                    fieldName: "MP06024a_B",
                    label: "Democrat",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06025a_B",
                    label: "Republican",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "MP06026a_B",
                    label: "Independent/Other",
                    format: {
                      digitSeparator: true,
                      places: 0
                    fieldName: "POP18UP_CY",
                    label: "Adult Population",
                    format: {
                      digitSeparator: true,
                      places: 0
        const map = new Map({
          basemap: "dark-gray-vector",
          layers: [layer]
        const view = new MapView({
          container: "viewDiv",
          map: map,
          center: [-95, 38],
          zoom: 4
        const legend = new Legend({
          view: view,
          layerInfos: [
              layer: layer,
              title: "Dominant political party by number of registered voters for each U.S. County"
        view.ui.add(new Expand({
          content: legend
        }), "top-right");
        // Creates a SimpleFillSymbol based on an input color
        function createSymbol(color) {
          return {
            type: "simple-fill", // autocasts as new SimpleFillSymbol()
            color: color,
            outline: {
              width: 0.2,
              color: [0, 0, 0, 0.1]
    </script>
  </head>

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

See the Arcade - expression language guide for more details about how to use Arcade in other parts of the ArcGIS API for JavaScript.

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