Visual variables

Weather stations styled with a simple render and visual variables to show air temperature

What are visual variables?

Visual variables are objects that allow you to override one or more properties of a renderer's symbols based on a numeric data value returned from a field or an expression. This is an alternative to visualizing numeric data with a class breaks style. Rather than separate values into discrete ranges of data, visual variables linearly interpolate between data stops to create a smooth, continuous (unclassed) visualization.

There are four visual variables that can be overridden with data values.

  1. Color
  2. Size
  3. Opacity
  4. Rotation

How visual variables work

All visual variables are added to a renderer's visualVariables property. A renderer can contain more than one visual variable, but adding more than one at a time may cause confusion.

Multivariate visualizations

Learn how to effectively use multiple visual variables in a single renderer.

Color

A color variable overrides the color of a symbol based on a numeric data value returned from a field or expression along a continuous color ramp. Numeric data should be normalized before visualizing it with color, especially for polygon layers.

Color visual variables require the following:

  1. A reference to a data value either from a field name, or an Arcade expression.
  2. At least two color stops that match data values to colors. The colors of symbols with data values between the designated stops are linearly interpolated.

The following example renders the current temperature reported by weather stations along a continuous color ramp.

ArcGIS JS API
55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 56 57 58 59 60 61 62 63 64 65 66 67 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
<!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: Visual variables (color)</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

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

    <script>
      require([
        "esri/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        esriConfig,
        Map,
        MapView,
        FeatureLayer,
        Legend,
        Expand
      ) {

        esriConfig.apiKey = "YOUR-API-KEY";

        const referenceScale = 9244650*4;


        const renderer = {
          type: "simple",
          symbol: {
            type: "simple-marker",
            style: "circle",
            color: [250, 250, 250],
            outline: {
              color: [255, 255, 255, 0.5],
              width: 0.5
            },
            size: "8px"
          },

          visualVariables: [
            {
              type: "color",
              field: "TEMP",
              stops: [
                { value: 20, color: "#2b83ba" },
                { value: 35, color: "#abdda4" },
                { value: 50, color: "#ffffbf" },
                { value: 65, color: "#fdae61" },
                { value: 80, color: "#d7191c" }
              ]
            }
          ]

        };


        // Set the renderer on the feature layer
        const layer = new FeatureLayer({
          portalItem: {
            id: "cb1886ff0a9d4156ba4d2fadd7e8a139"
          },
          title: "Current weather conditions",
          renderer: renderer
        });

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

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

        view.ui.add(new Expand({
          content: new Legend({
            view: view
          }),
          view: view,
          expanded: false
        }), "top-right");

      });
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Size

A size variable overrides the size of a symbol based on a numeric data value returned from a field or expression. This does not apply to renderers with fill symbols. To visualize a polygon layer by size, you should use a marker symbol, which will be rendered at the centroid of the polygon.

The size visual variable can be defined in two different ways:

  1. With size stops, or
  2. Matching a maxDataValue with a maxSize, and a minDataValue with a minSize.

Size visual variables require the following:

  1. A reference to a data value either from a field name, or an Arcade expression.
  2. At least two size stops that match data values to sizes. The sizes of symbols with data values between the designated stops are linearly interpolated.

The following example renders the current wind speed reported by weather stations along a continuous size ramp.

ArcGIS JS API
53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 53 54 55 56 57 58 59 60 61 62 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
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Size visual variable</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

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

    <script>
      require([
        "esri/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        esriConfig,
        Map,
        MapView,
        FeatureLayer,
        Legend,
        Expand
      ) {
        esriConfig.apiKey = "YOUR-API-KEY";
        const referenceScale = 9244650*2;


        const renderer = {
          type: "simple",
          symbol: {
            type: "simple-marker",
            style: "circle",
            color: [50, 50, 50, 0.4],
            outline: {
              color: [255, 255, 255, 0.3],
              width: 0.2
            },
            size: "8px"
          },

          visualVariables: [
            {
              type: "size",
              field: "WIND_SPEED",
              minDataValue: 5,
              maxDataValue: 60,
              minSize: 4,
              maxSize: 22
            }
          ]

        };


        // Set the renderer on the feature layer
        const layer = new FeatureLayer({
          portalItem: {
            id: "cb1886ff0a9d4156ba4d2fadd7e8a139"
          },
          title: "Current weather conditions",
          renderer: renderer
        });

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

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

        view.ui.add(new Expand({
          content: new Legend({
            view: view
          }),
          view: view,
          expanded: false
        }), "top-right");
      });
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Rotation

A rotation variable sets the rotation of a symbol based on a numeric data value returned from a field or expression. This is typically done to rotate symbols that indicate directionality, such as:

  • wind direction
  • traffic flow
  • aspect

Rotation visual variables are different from other visual variables in that they only require a data value without the need for stops.

  1. A reference to a data value either from a field name, or an Arcade expression.
  2. An optional rotation type indicating a geometry or arithmetic rotation.

The following example visualizes weather stations with arrow markers and rotates them based on wind direction.

ArcGIS JS API
55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 56 57 58 59 60 61 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>Rotation visual variable</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

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

    <script>
      require([
        "esri/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        esriConfig,
        Map,
        MapView,
        FeatureLayer,
        Legend,
        Expand
      ) {
        esriConfig.apiKey = "YOUR-API-KEY";
        const referenceScale = 9244650*2;


        const renderer = {
          type: "simple",
          symbol: {
            type: "simple-marker",
            // Arrow marker defined as SVG path
            path: "M14.5,29 23.5,0 14.5,9 5.5,0z",
            color: [50, 50, 50],
            outline: {
              color: [255, 255, 255, 0.5],
              width: 0.5
            },
            angle: 180,
            size: "20px"
          },

          visualVariables: [
            {
              type: "rotation",
              field: "WIND_DIRECT",
              rotationType: "geographic"
            }
          ]

        };


        // Set the renderer on the feature layer
        const layer = new FeatureLayer({
          portalItem: {
            id: "cb1886ff0a9d4156ba4d2fadd7e8a139"
          },
          title: "Current weather conditions",
          renderer: renderer
        });

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

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

        view.ui.add(new Expand({
          content: new Legend({
            view: view
          }),
          view: view,
          expanded: false
        }), "top-right");

      });
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Opacity

An opacity variable overrides the opacity of a symbol based on a numeric data value returned from a field or expression. This variable is typically used to subdue features or make some more prominent than others.

Opacity visual variables require the following:

  1. A reference to a data value either from a field name or an Arcade expression.
  2. At least two opacity stops that match data values to opacity values between 0 and 1. The opacity of symbols with data values between the designated stops are linearly interpolated.

The following example visualizes the predominant crop for each U.S. county. The renderer has an opacity variable to emphasize counties with a lot of cropland and subdue counties that have very little cropland by comparison.

ArcGIS JS API
74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
<!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: Visual variables (opacity)</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

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

    <script>
      require([
        "esri/config",
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand"
      ], function(
        esriConfig,
        Map,
        MapView,
        FeatureLayer,
        Legend,
        Expand
      ) {

        esriConfig.apiKey = "YOUR-API-KEY";

        const referenceScale = 9244650*2;

        function createSymbol(color){
          return {
            type: "simple-fill",
            outline: {
              color: "rgba(50,50,50,0.1)",
              width: 0.5
            },
            color,
            style: "solid"
          }
        }


        const renderer = {
          type: "unique-value",
          field: "DOM_CROP_ACRES",
          uniqueValueInfos: [{
            value: "Corn",
            symbol: createSymbol("#e6d800")
          }, {
            value: "Wheat",
            symbol: createSymbol("#9b19f5")
          }, {
            value: "Soybeans",
            symbol: createSymbol("#0bb4ff")
          }, {
            value: "Cotton",
            symbol: createSymbol("#50e991")
          }, {
            value: "Vegetables",
            symbol: createSymbol("#e60049")
          }],

          visualVariables: [
            {
              type: "opacity",
              field: "TotalFarmedAcres",
              normalizationField: "AREA_ACRES",
              legendOptions: {
                showLegend: false,
              },
              stops: [
                { value: 0.0, opacity: 0.2 },
                { value: 0.1, opacity: 0.5 },
                { value: 0.5, opacity: 0.8 },
                { value: 0.9, opacity: 1.0 }
              ]
            }
          ]

        };


        // Set the renderer on the feature layer
        const layer = new FeatureLayer({
          url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/US_county_crops_2007_clean/FeatureServer/0",
          title: "U.S. counties",
          renderer: renderer
        });

        const map = new Map({
          basemap: "arcgis-dark-gray",
          layers: [layer]
        });

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

        view.ui.add(new Expand({
          content: new Legend({
            view: view
          }),
          view: view,
          expanded: false
        }), "top-right");
      });
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>