Class breaks

Census tracts styled with a class breaks renderer displaying the level of high school education

What is a class breaks style?

The class breaks style allows you to visualize numeric ranges of data. It involves defining meaningful ranges of numbers into two or more classes, representing each class with a unique symbol. You can use this style to answer questions beginning with how much?

While a class break's symbol is distinct from another class break's symbol, symbols are typically similar to one another in all aspects with the exception of one property, such as color.

How a class breaks style works

This style is configured with a class breaks renderer. This renderer requires the following:

  1. A reference to a data value either from a field name, or an Arcade expression.
  2. A list of class break info objects that match a unique symbol with a range of expected values returned from the field or expression.

For visualizations with light basemaps or backgrounds, classes representing smaller numbers are typically represented with light colors and classes representing larger numbers are represented with dark colors.

There are several classification methods that can be employed in the creation of this renderer, but defining class breaks in code typically involves manual classification.

Classified visualizations are ideal for maps where predefined breaks hold meaning to the end user. The range for each class and the number of classes should be deliberate choices made after careful consideration.

Examples

Normalize by attribute

This example demonstrates how to visualize ranges of numeric data values normalized by another data attribute. In the vast majority of cases, you should not normalize total counts with polygon data. These values should be normalized by a base value or the area of the polygon.

This app visualizes the percentage of people age 25 and older that did not attend any high school classes.

  1. Create a class breaks renderer.
  2. Reference a numeric field name containing the total number of people that did not complete high school.
  3. Reference a normalizationField, in this case, the total number of people age 25 and older. The value of field will be divided by the value of normalizationField.
  4. Create four class break info objects and assign a symbol to each range of values.
  5. You can optionally add a default symbol to represent all values that don't fall within one of the breaks.
ArcGIS JS APIArcGIS .NET APIArcGIS Android APIArcGIS iOS APIArcGIS Java APIArcGIS Qt API (C++)ArcGIS Qt API (QML)
                                                                                                                                              
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>
      ArcGIS Developer Guide: Class breaks
    </title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.20//esri/themes/light/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/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
      ], (esriConfig, Map, MapView, FeatureLayer, Legend, Expand)=> {
        esriConfig.apiKey = "YOUR_API_KEY";
        function createSymbol(color){
          return {
            type: "simple-fill",
            style: "solid",
            outline: {
              width: 0.2,
              color: [255, 255, 255, 0.2]
        const renderer = {
          type: "class-breaks",
          field: "NOHS_CY",
          normalizationField: "EDUCBASECY",
          legendOptions: {
            title: "% of adults with no high school education"
          },
          defaultSymbol: {
            type: "simple-fill",
            color: "black",
            style: "backward-diagonal",
            outline: {
              width: 0.5,
              color: [50, 50, 50, 0.6]
            }
          },
          defaultLabel: "no data",
          classBreakInfos: [
            {
              minValue: 0,
              maxValue: 0.04999,
              symbol: createSymbol("#edf8fb"),
              label: "< 5%"
            },
            {
              minValue: 0.05,
              maxValue: 0.14999,
              symbol: createSymbol("#b3cde3"),
              label: "5 - 15%"
            },
            {
              minValue: 0.15,
              maxValue: 0.24999,
              symbol: createSymbol("#8c96c6"),
              label: "15 - 25%"
            },
            {
              minValue: 0.25,
              maxValue: 1.0,
              symbol: createSymbol("#88419d"),
              label: "> 25%"
            }
          ]
        };
        const layer = new FeatureLayer({
          portalItem: {
            id: "1cbb0faa0f1f424bbe213bfae9319309"
          title: "Census tracts",
          renderer: renderer,
          popupTemplate: {
            content: "{NOHS_CY} adults 25 years old and older in this census tract did not attend high school."
          opacity: 1
        const map = new Map({
          basemap: {
            portalItem: {
              id: "3582b744bba84668b52a16b0b6942544"
          layers: [ layer ],
          constraints: {
            snapToZoom: false
        const view = new MapView({
          container: "viewDiv",
          map: map,
          scale: 577790,
          center: [-117.8099, 34.0441]
        const legend = new Legend({
          view: view
        view.ui.add(new Expand({
          view: view,
          content: legend,
          expanded: true
        }), "top-right");
    </script>
  </head>

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

Normalize by area

This example demonstrates how to visualize ranges of values normalized by the area of each polygon. This app visualizes the number of households per square mile. This value is calculated client-side using an Arcade expression. First, write the Arcade expression.

                                                                                                                                           
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>
      ArcGIS Developer Guide: Class breaks-Arcade
    </title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.20//esri/themes/light/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/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
      ], (esriConfig, Map, MapView, FeatureLayer, Legend, Expand)=> {

        esriConfig.apiKey = "YOUR_API_KEY";
        function createSymbol(color){
          return {
            type: "simple-fill",
            color,
            style: "solid",
            outline: {
              width: 0.2,
              color: [255, 255, 255, 0.2]
            }
          };
        }


        const renderer = {
          type: "class-breaks",
          valueExpression: `

            $feature.TOTHH_CY / AreaGeodetic($feature, 'square-miles');

          `,
          valueExpressionTitle: "Households per square mile",
          classBreakInfos: [
            {
              minValue: 0,
              maxValue: 2500,
              symbol: createSymbol("#edf8fb"),
              label: "< 2,500"
            },
            {
              minValue: 2500,
              maxValue: 5000,
              symbol: createSymbol("#b3cde3"),
              label: "2,500 - 5,000"
            },
            {
              minValue: 5000,
              maxValue: 10000,
              symbol: createSymbol("#8c96c6"),
              label: "5000 - 10,000"
            },
            {
              minValue: 10000,
              maxValue: 1000000,
              symbol: createSymbol("#88419d"),
              label: "> 10,000"
            }
          ]
        };


        const layer = new FeatureLayer({
          portalItem: {
            id: "1cbb0faa0f1f424bbe213bfae9319309"
          },
          title: "Census tracts",
          renderer: renderer,
          popupTemplate: {
            content: "{TOTHH_CY} households are in this census tract.",
            fieldInfos: [{
              fieldName: "TOTHH_CY",
              format: {
                places: 0,
                digitSeparator: true
              }
            }]
          },
          opacity: 1
        });

        const map = new Map({
          basemap: {
            portalItem: {
              id: "3582b744bba84668b52a16b0b6942544"
            }
          },
          layers: [ layer ]
        });

        const view = new MapView({
          container: "viewDiv",
          map: map,
          scale: 577790,
          center: [-117.8099, 34.0441],
          constraints: {
            snapToZoom: false
          }
        });

        const legend = new Legend({
          view: view
        });

        view.ui.add(new Expand({
          view: view,
          content: legend,
          expanded: true
        }), "top-right");
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
  </body>
</html>
  1. Create a class breaks renderer.
  2. Reference the Arcade expression in the valueExpression property.
  3. Create four class break info objects and assign a symbol to each range of values.
  4. You can optionally add a default symbol to represent all values that don't fall within one of the breaks.
ArcGIS JS API
                                                                                                                                           
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>
      ArcGIS Developer Guide: Class breaks-Arcade
    </title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.20//esri/themes/light/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/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
      ], (esriConfig, Map, MapView, FeatureLayer, Legend, Expand)=> {
        esriConfig.apiKey = "YOUR_API_KEY";
        function createSymbol(color){
          return {
            type: "simple-fill",
            style: "solid",
            outline: {
              width: 0.2,
              color: [255, 255, 255, 0.2]
        const renderer = {
          type: "class-breaks",
          valueExpression: `

            $feature.TOTHH_CY / AreaGeodetic($feature, 'square-miles');

          `,
          valueExpressionTitle: "Households per square mile",
          classBreakInfos: [
            {
              minValue: 0,
              maxValue: 2500,
              symbol: createSymbol("#edf8fb"),
              label: "< 2,500"
            },
            {
              minValue: 2500,
              maxValue: 5000,
              symbol: createSymbol("#b3cde3"),
              label: "2,500 - 5,000"
            },
            {
              minValue: 5000,
              maxValue: 10000,
              symbol: createSymbol("#8c96c6"),
              label: "5000 - 10,000"
            },
            {
              minValue: 10000,
              maxValue: 1000000,
              symbol: createSymbol("#88419d"),
              label: "> 10,000"
            }
          ]
        };
        const layer = new FeatureLayer({
          portalItem: {
            id: "1cbb0faa0f1f424bbe213bfae9319309"
          title: "Census tracts",
          renderer: renderer,
          popupTemplate: {
            content: "{TOTHH_CY} households are in this census tract.",
            fieldInfos: [{
              fieldName: "TOTHH_CY",
              format: {
                places: 0,
                digitSeparator: true
          opacity: 1
        const map = new Map({
          basemap: {
            portalItem: {
              id: "3582b744bba84668b52a16b0b6942544"
          layers: [ layer ]
        const view = new MapView({
          container: "viewDiv",
          map: map,
          scale: 577790,
          center: [-117.8099, 34.0441],
          constraints: {
            snapToZoom: false
        const legend = new Legend({
          view: view
        view.ui.add(new Expand({
          view: view,
          content: legend,
          expanded: true
        }), "top-right");
    </script>
  </head>

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

Graduated point symbols in 3D

This example visualizes earthquakes on a globe based on their magnitude. The goal of this map is to show the major earthquakes that cause severe damage, the moderate ones that cause damage only to buildings which are not earthquake proof, and small earthquakes that don't cause any serious damage. A class breaks renderer with three classes based on the magnitude ranges is the most suitable to see these types of earthquakes at a glance.

Steps

  1. Create three classes for high magnitude earthquakes (greater than 7), moderate magnitude (greater than 5 and less than 7) and small magnitude (less than 5).
  2. Assign an intuitive symbol to each of the classes.
  3. Set these classes on a class breaks renderer.
  4. Assign the renderer to the earthquake layer.
ArcGIS JS APIArcGIS .NET APIArcGIS Android APIArcGIS iOS APIArcGIS Java APIArcGIS Qt API (C++)ArcGIS Qt API (QML)
                                                                                                                                                                                                 
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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>
      ArcGIS Developer Guide: Class breaks (3D)
    </title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.20//esri/themes/light/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/config",
        "esri/Map",
        "esri/layers/GeoJSONLayer",
        "esri/views/SceneView",
        "esri/Basemap",
        "esri/layers/TileLayer",
        "esri/widgets/Legend",
      ],(esriConfig, Map, GeoJSONLayer, SceneView, Basemap, TileLayer, Legend)=> {
        esriConfig.apiKey = "YOUR_API_KEY";
        const map = new Map({
          basemap: new Basemap({
            baseLayers: [
              new TileLayer({
                url:
                  "https://tiles.arcgis.com/tiles/nGt4QxSblgDfeJn9/arcgis/rest/services/VintageShadedRelief/MapServer",
                opacity: 0.7,
                minScale: 0,
          ground: {
            surfaceColor: [255, 255, 255],
        const view = new SceneView({
          container: "viewDiv",
          camera: {
            position: [-96.22, 15.26, 20000000],
            heading: 0,
            tilt: 0,
          qualityProfile: "high",
          map: map,
          alphaCompositingEnabled: true,
          environment: {
            background: {
              type: "color",
              color: [0, 0, 0, 0],
            lighting: {
              date:
                "Sun Jul 15 2018 21:04:41 GMT+0200 (Central European Summer Time)",
            starsEnabled: false,
            atmosphereEnabled: false,
          highlightOptions: {
            fillOpacity: 0,
            color: "#ffffff",
          constraints: {
            altitude: {
              min: 400000,
        const url =
          "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson";
        const earthquakesLayer = new GeoJSONLayer({
          url: url,
          copyright: "USGS Earthquakes",
          screenSizePerspectiveEnabled: false,
          title: "Earthquakes in the last 30 days",
          popupTemplate: {
            title: "Earthquake Info",
            content:
              "Magnitude <b>{mag}</b> {type} hit <b>{place}</b> on <b>{time}</b>",
            fieldInfos: [
                fieldName: "time",
                format: {
                  dateFormat: "short-date-short-time",
        // the symbol for each earthquake class is composed of multiple symbol layers
        const baseSymbolLayer = {
          type: "icon",
          resource: { primitive: "circle" },
          material: { color: [245, 116, 73, 0.9] },
          size: 3,
        const secondSymbolLayer = {
          type: "icon",
          resource: { primitive: "circle" },
          material: { color: [245, 116, 73, 0] },
          outline: { color: [245, 116, 73, 0.7], size: 1 },
          size: 20,
        const thirdSymbolLayer = {
          type: "icon",
          resource: { primitive: "circle" },
          material: { color: [245, 116, 73, 0] },
          outline: { color: [245, 116, 73, 0.5], size: 1 },
          size: 40,
        const renderer = {
          type: "class-breaks",
          field: "mag",
          legendOptions: {
            title: "Legend",
          },
          classBreakInfos: [
            {
              minValue: -2,
              maxValue: 5,
              symbol: {
                type: "point-3d",
                symbolLayers: [baseSymbolLayer],
              },
              label: "Magnitude < 5",
            },
            {
              minValue: 5,
              maxValue: 7,
              symbol: {
                type: "point-3d",
                symbolLayers: [baseSymbolLayer, secondSymbolLayer],
              },
              label: "Magnitude between 5 and 7",
            },
            {
              minValue: 7,
              maxValue: 10,
              symbol: {
                type: "point-3d",
                symbolLayers: [
                  baseSymbolLayer,
                  secondSymbolLayer,
                  thirdSymbolLayer,
                ],
              },
              label: "Magnitude larger than 7",
            },
          ],
        };

        earthquakesLayer.renderer = renderer;
        const legend = new Legend({
          view: view,
        view.ui.add(legend, "top-right")
    </script>
  </head>

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

Tutorials

Learn how to build and style layers with step-by-step tutorials.

Services

Different APIs have different levels of support for data-driven visualization.

Unique typesClass breaksVisual variablesTimeMultivariatePredominanceDot densityRelationship
ArcGIS API for JavaScriptFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedFully supported
ArcGIS Runtime API for AndroidFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for iOSFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for JavaFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for .NETFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for QtFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS API for PythonFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
Full supportPartial support (see notes)Not supported

API support

Different APIs have different levels of support for data-driven visualization.

Unique typesClass breaksVisual variablesTimeMultivariatePredominanceDot densityRelationship
ArcGIS API for JavaScriptFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedFully supported
ArcGIS Runtime API for AndroidFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for iOSFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for JavaFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for .NETFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS Runtime API for QtFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
ArcGIS API for PythonFully supportedFully supportedFully supportedFully supportedFully supportedFully supportedNot supportedFully supported
Full supportPartial support (see notes)Not supported

Tools

Use tools such as Map Viewer and Scene Viewer to create and style web maps and web scenes for your applications.

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