Arcade

What is Arcade?

Arcade is an expression language that can perform mathematical calculations and evaluate logical statements in visualizations, popup content, and labels within ArcGIS apps (i.e. ArcGIS Pro, ArcGIS Online, the ArcGIS Runtime APIs, and the ArcGIS Maps SDK for JavaScript). When an expression is authored in one of these products, it can be saved to a webmap, loaded, and evaluated in other apps. This gives you flexibility for defining custom content that can be persisted and evaluated consistently in any ArcGIS application.

How to write Arcade expressions

In many respects Arcade's syntax is similar to JavaScript, allowing you to declare variables, perform logical operations, take advantage of built-in functions, and write custom functions. However, there are key differences between the two languages. Read the full Arcade documentation including guides and the function reference for details on how to write an Arcade expression. You also have access to a playground that provides an environment for testing expressions with test datasets.

Profile variables give expressions access to data values connected to a layer, map, or workspace. These values are the inputs to the expression, required for producing a valid return value as defined by the expression author. For example $feature provides expressions access to a feature's attributes and geometries.

Within JavaScript apps, Arcade expressions are always referenced as a string value. When writing single-line expressions, you can simply wrap it in double or single quotes.

Use dark colors for code blocksCopy
1
2
// returns the % of the population that is age 18 and older
renderer.valueExpression = "Round( ($feature.AGE_18UP / $feature.TOTAL_POP) * 100 )";

You can use template literals (ES6 or later) to write multi-line Arcade expressions.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
renderer.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;
`;

Keep in mind that Arcade text values also support template literals. Since Arcade expressions are stored as strings in the ArcGIS Maps SDK for JavaScript, they are often written using template literals in JavaScript. You can still use Arcade template literals inside a JavaScript template literal, but you will need to escape key characters such as backticks and dollar signs for the Arcade template literals to be recognized. For example, note the Arcade expression that uses a template literal within a JavaScript template literal in a PopupTemplate:

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
layer.popupTemplate = {
  content: "{expression/percent-unemployed}",
  expressionInfos: [
    {
      name: "percent-unemployed",
      title: "Percent unemployed",
      expression: `
        var unemploymentRate = ( $feature.UNEMP_CY / $feature.LABOR_FORCE ) * 100;
        var population = $feature.POP_16UP;
        var populationNotWorking = ( ( $feature.UNEMP_CY + $feature.NOT_LABORFORCE_16 ) / $feature.POP_16UP ) * 100;

        // returns a string built using an Arcade template literal

        return \`\${$feature.COUNTY} County

        - Unemployment rate: \${Text(unemploymentRate, "##.#")}%
        - % population not working: \${Text(populationNotWorking, "##.#")}%
        - Population: \${Text(population, "#,###")}\`
      `
    }
  ]
};

The Summarize intersecting points in a popup sample demonstrates another example of Arcade template literals. If you aren't writing ES6 code, you can place the expression in a separate <script> tag outside the JavaScript, and set the type to text/plain with a unique ID to reference the script in the appropriate place within JavaScript.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
<script type="text/plain" id="adult-population">
  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;
</script>

Then reference the script as a string value by calling the document.getElementById() method.

Use dark colors for code blocksCopy
1
renderer.valueExpression = document.getElementById("adult-population").text;

See the example snippets below and the Create a custom visualization using Arcade sample for more context.

Where can I use Arcade?

Arcade can only be executed within a valid profile. Profiles define rules or specifications for writing a valid expression. This includes defining the valid data inputs (profile variables), supported functions, and return types in addition to the context where they can execute.

Arcade is self-contained and executes on a feature-by-feature basis. Profiles ensure expressions are secure and performant given the context in which they execute. For example, Arcade allows you to define data values driving a visualization. If your layer has 100,000 features and has a renderer defined with an Arcade expression, that expression must execute 100,000 times to properly render the data. Because of this, the visualization profile prevents you from accessing data from sources outside the original feature since this would severely slow down app performance. In popups, however, you can access data from any layer in a map or service within an Arcade expression because you can performantly do so since only one expression executes at a time (when the popup is opened).

The following sections below describe the places in the JavaScript API where you can write Arcade expressions. Each provides links to the profile specification defining expression rules given the context along with live examples.

Labeling

Arcade is used to create label expressions for features in a FeatureLayer or SceneLayer. Starting at version 4.5 of the API, this is the only supported method for labeling features. You must add at least one LabelClass to the labelingInfo property of the layer. The Arcade expression must be passed as a string value to the expression property of the LabelClass's labelExpressionInfo object.

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
// returns the value of a field in the layer
// the value of this field will be the label for each feature
const arcade = "$feature.STATION_NAME";

// this object autocasts as new LabelClass()
const labelClass = {
  // set the arcade expression to the `expression` property of labelExpressionInfo
  labelExpressionInfo: {
    expression: arcade
  },
  labelPlacement: "below-right",
  minScale: 2500000,
  symbol: {
    type: "label-3d",
    symbolLayers: [{
      type: "text",
      material: { color: "white" },
      halo: {
        color: "black",
        size: 1
      },
      size: 8
    }]
  }
};

// set the label class to the feature layer
featureLayer.labelingInfo = [ labelClass ];

Label expressions written in Arcade may be more complex, containing multiple lines that perform mathematical and logical operations. For example, the Multi-line labels sample demonstrates how to construct a more complex multi-line label expression. This expression assigns two numeric field values to their own variables, evaluates them, and returns a string value. Arcade's When() function is used to evaluate the wind direction (between 0-360 degrees), which returns the associated compass direction of either N, NE, E, SE, S, SW, W, or NW. If the wind speed is 0, then no direction is returned. The final line of the expression returns the label, which is the value of the WIND variable.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/plain" id="wind-direction">
  var DEG = $feature.WIND_DIRECT;
  var SPEED = $feature.WIND_SPEED;
  var DIR = When( SPEED == 0, '',
    (DEG < 22.5 && DEG >= 0) || DEG > 337.5, 'N',
     DEG >= 22.5 && DEG < 67.5, 'NE',
     DEG >= 67.5 && DEG < 112.5, 'E',
     DEG >= 112.5 && DEG < 157.5, 'SE',
     DEG >= 157.5 && DEG < 202.5, 'S',
     DEG >= 202.5 && DEG < 247.5, 'SW',
     DEG >= 247.5 && DEG < 292.5, 'W',
     DEG >= 292.5 && DEG < 337.5, 'NW', '' );
  var WIND = SPEED + ' mph ' + DIR;
  return WIND;
</script>

There are many additional Arcade functions useful for labeling, including text functions that provide logic for text formatting. Be sure to check out the full Arcade documentation for more information regarding these built-in functions.

Popups

Arcade is implemented in two popup profiles:

  • Popup - For calculating attributes to display in a layer's popup content or a feature reduction popup. This is useful for simple calculations.
  • Popup Element - For conditionally creating popup elements in a layer's popup or a feature reduction popup. This should be used if you want a single expression to return multiple values in a single popup element.

Arcade expressions can be referenced within the content of a PopupTemplate. This is useful for situations when you want to display data that isn't present as an attribute value in your layer. In the popup profile, expressions must return a text or a number value, and may access a feature's attributes with $feature, or data from other features and layers using $layer, $map, and $datastore.

For example, the Reference Arcade expressions in PopupTemplate sample displays a layer containing labor statistics for each U.S. county. Some attributes include unemployment rate, population, and the number of people participating in the labor force. It does not have an attribute for labor force participation rate. We can use Arcade to calculate that for us at runtime.

Use dark colors for code blocksCopy
1
2
// labor force participation rate
Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)

The value returned from this expression can be displayed in the layer's popupTemplate. To view the value in the popup, we must reference it in the expressionInfos property of the PopupTemplate and assign it a name and a title.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
layer.popupTemplate = {
  expressionInfos: [{
    name: "participation-rate",
    title: "% of population 16+ participating in the labor force",
    expression: "Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)"
  }],
  content: "In {NAME} county, {expression/participation-rate}% of the population"
    + " participates in the labor force."
};

Notice that once the expression exists in the expressionInfos property, you can reference the value returned from the expression using the {expression/expression-name} placeholder template within the content of the PopupTemplate. The Popup's content would display the following after the user clicked a feature representing Greenlee, AZ:

arcade-popup-text

You can also reference values returned from Arcade expressions inside popup content elements, including FieldsContent, MediaContent, and TextContent. Just reference the name of the expression in the fieldName property of the object. Remember to use the expression/expression-name syntax.

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
layer.popupTemplate = {
  expressionInfos: [{
    name: "participation-rate",
    title: "% of population 16+ participating in the labor force",
    expression: "Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)"
  }],
  content: [{
    type: "fields",
    fieldInfos: [{
      fieldName: "expression/participation-rate"
    }, {
      fieldName: "CIVLBFR_CY",
      label: "Civilian labor force",
      format: {
        places: 0,
        digitSeparator: true
      }
    }, {
      fieldName: "POP_16UP",
      label: "Population 16+",
      format: {
        places: 0,
        digitSeparator: true
      }
    }]
  }]
};

The popup will display the following:

arcade-popup-table

View the Reference Arcade expressions in PopupTemplate sample to see this workflow in the context of a live sample.

Feature Reduction Popup

In addition to layer popups, Arcade expressions can be referenced within the content of a cluster popupTemplate. This is slightly different than layer popups because $feature represents the cluster itself, which summarizes two or more features.

$feature always contains the cluster_count field, in addition to other fields that summarize the layer's renderer (e.g. cluster_avg_fieldName).

Use dark colors for code blocksCopy
1
2
// returns the sum of the cost field for all features in the cluster
$feature.cluster_count * $feature.cluster_avg_cost

This profile also gives you access to the features contained within the cluster via the $aggregatedFeatures profile variable. You can filter the aggregated features, iterate through them, sort them, and calculate statistics with them.

Use dark colors for code blocksCopy
1
2
3
4
// returns the total number of car crashes
// that resulted in at least one fatality in a
// cluster representing motor vehicle accidents
Count(Filter($aggregatedFeatures, "FATALITIES > 0"))

The values returned from these expressions can be displayed in the cluster's popupTemplate. To view the value in the popup, you must reference it in the expressionInfos property of the PopupTemplate and assign it a name and a title.

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
layer.featureReduction = {
  type: "cluster",
  popupTemplate: {
    expressionInfos: [{
      name: "total-cost",
      title: "Total damages",
      expression: "Text($feature.cluster_count * $feature.cluster_avg_cost, '$#,###.##')"
    }, {
      name: "fatalities",
      title: "Crashes with fatalities",
      expression: `
        Expects($aggregatedFeatures, 'FATALITIES')
        Count(Filter($aggregatedFeatures, 'FATALITIES > 0'))
      `
    }],
    content: `
      This cluster represents {cluster_count} motor vehical accidents. {expression/fatalities} of these crashes
      had at least one fatality. These crashes resulted in {expression/total-cost} of damages.
    `
  }
};

Notice that once the expression exists in the expressionInfos property, you can reference the value returned from the expression using the {expression/expression-name} string template within the content of the PopupTemplate.

View the Clustering - filter popup features sample to see this profile in action.

The popup element profile allows map authors to write expressions that return a dictionary (i.e. an object) representing either a rich text, fields, or media (i.e. a chart) popup content element. The returned dictionary must follow the Web Map Specification for a popupElement. Unlike the Popup profile, this profile allows popup authors to return multiple values within a single element.

In this profile, expressions must return a dictionary, and may access a feature's attributes with $feature, or data from other features and layers using $layer, $map, and $datastore.

This profile is useful in advanced scenarios where content in charts, tables, or rich text elements is based on logical conditions. For example, the following expression creates a fields content element containing only fields that have data values. This may be significantly more condensed than a standard FieldsContent element, which doesn't give you the ability to check whether a field is empty.

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
// Creates a table with only fields that contain data
var fields = Schema($feature).fields;
function getNames(field){
  return field.name;
}
function filterValidFields(fieldName){
  var invalidNames = ["objectid", "fid", "shape__area", "shape__length"];
  return !includes(invalidNames, lower(fieldName)) && !IsEmpty($feature[fieldName]) && !IsNan($feature[fieldName]);
}

var validFields = Filter(Map(fields, getNames), filterValidFields);
var attributes = {};
var fieldInfos = [];

for (var f in validFields){
  var fieldName = validFields[f];
  Push(fieldInfos, { fieldName: fieldName });
  // format numbers with digit separator and one decimal place
  var value = IIF(TypeOf($feature[fieldName] == "Number"), Text($feature[fieldName], "#,#.#"), $feature[fieldName]);
  attributes[fieldName] = value;
}

return {
  type: "fields",
  fieldInfos: fieldInfos,
  attributes: attributes
};

Popup element expressions are defined in the expressionInfo property of an ExpressionContent element.

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
// Creates an column chart where each category/value
// is an aggregate of two or more fields
layer.popupTemplate = {
  title: "Educational Attainment",
  content: [{
    type: "expression",
    expressionInfo: {
      expression: `
        // Create a dictionary of attributes representing the values
        // to display in the chart
        var attributes = {
          "No School": $feature.no_school + $feature.some_primary,
          "Primary": $feature.primary_complete + $feature.some_secondary,
          "Secondary": $feature.secondary_complete + $feature.some_highSchool,
          "High School": $feature.highSchool_diploma + $feature.highSchool_ged + $feature.some_college,
          "College/University": $feature.associates + $feature.bachelors + $feature.masters + $feature.doctorate + $feature.professional;
        };

        var fields = [];

        // Create an array representing the attribute names (or keys)
        for (var k in attributes){
          Push(fields, k);
        }

        // Returns a dictionary providing the information
        // required by the popup to render a column chart
        return {
          type: "media",
          attributes: attributes,
          title: "Educational attainment",
          mediaInfos: [{
            type: "columnchart",
            value: {
              // The list of attribute names (keys) to include in the chart
              fields: fields
            }
          }]
        };
      `,
      title: "Educational Attainment"
    }
  }]
};

You can also use this element to create charts or other content types consisting of aggregated data values. This can be especially useful in FeatureReductionCluster popups. The following examples describe the various content types you can define in an Arcade expression.

Visualization

In the Visualization profile, Arcade allows you to calculate values for each feature in a layer at runtime and use those values for a data-driven visualization. This is an alternative approach to creating data-driven visualizations based on a single field in the layer. To accomplish this, an Arcade expression may be passed to the valueExpression property in a ClassBreaksRenderer, UniqueValueRenderer or any of the visual variables: color, size, opacity, and rotation instead of referencing a field/normalizationField. You can also use Arcade to override a CIMSymbol's properties in the valueExpressionInfo.expression property of the symbol's primitiveOverrides.

When used in a ClassBreaksRenderer or any of the visual variables, the expression may access a feature's attributes with $feature and must evaluate to a number. Expressions may evaluate to either strings or numbers in UniqueValueRenderer.

In the following snippet, a FeatureLayer representing U.S. counties is added to the map. The service has three fields that identify the number of republicans, democrats, and independent/non-party voters in each county. We can write an Arcade expression to color each county based on which party preference outnumbers the others.

First, write the Arcade expression in a script tag with a unique ID.

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
<script type="text/plain" id="winning-party">
  // Write the expression and reference the value
  // of each field with a meaningful variable name within
  // the expression. Then calculate the max number with
  // the Max() function and use Decode() to return a string
  // value representing the party whose field value matches
  // the max value.

  var republican = $feature.MP06025a_B;
  var democrat = $feature.MP06024a_B;
  var independent = $feature.MP06026a_B;
  var parties = [republican, democrat, independent];
  // Decode() and Max() are built-in Arcade functions
  return Decode( Max(parties),
    republican, 'republican',
    democrat, 'democrat',
    independent, 'independent',
    'n/a');
</script>

Then set the expression as a string value using document.getElementById() on the valueExpression property of a UniqueValueRenderer.

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
// Assign the expression to the `valueExpression` property and
// set up the unique value infos based on the decode values
// you set up in the expression.

const winnerArcade = document.getElementById("winning-party").text;

const renderer = new UniqueValueRenderer({
  valueExpression: winnerArcade,
  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/non-affiliated"
  }]
});

You can also add an opacity visual variable to the renderer to visualize the relative strength of the predominant party in each county. Counties where more people come from a single party will be drawn with high opacity, while those where the proportion of people from each party are relatively equal will be drawn with low opacity.

First, write the expression in a <script> tag.

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
<script type="text/plain" id="strength">
  // Write the expression and reference the value
  // of each field with a meaningful variable name within
  // the expression. Then calculate the max number with
  // the Max() function and the total using Sum().
  // Calculate the share of the max population within the
  // county. This value will be between 33 - 100 and will
  // be used to determine the feature's opacity.
  // Note the value is explicitly returned; it could also
  // be implicitly returned like the previous example

  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;
</script>

Then reference it in JavaScript as a string value.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Assign the expression to the `valueExpression` property and
// set up the unique value infos based on the decode values
// you set up in the expression.

const strengthArcade = document.getElementById("strength").text;

const opacityVV = {
  type: "opacity",
  valueExpression: strengthArcade,
  stops: [
    { value: 33, opacity: 0.1 },
    { value: 50, opacity: 1.0 }
  ]
};

// Add the visual variable to the renderer

renderer.visualVariables = [ opacityVV ];

View the Create a custom visualization using Arcade sample to see this example live.

Forms

Arcade is implemented in two form profiles:

  • Form Constraint - For indicating whether a field should be visible, editable, or required in a form.
  • Form Calculation - For calculating field values conditionally based on inputs from other fields.

Form Constraint

The Form Constraint profile is implemented in the FeatureForm widget, allowing you to indicate whether fields are visible, required, or editable during editing workflows. For example, instead of displaying all of the specified fields in various field configurations, you can configure certain fields to display conditionally using a visibility Arcade expression. A visibility expression allows you to access a feature's attributes with $feature and must return a Boolean value.

Expressions are defined in the expression property of an ExpressionInfo object. ExpressionInfos are set on the FormTemplate.expressionInfos property. To conditionally set the visibility of a form element, you must reference the expression name in the visibilityExpression property of the Element.

This profile is also implemented in the requiredExpression and editableExpression properties. These properties allow you to indicate whether a field is required or editable.

In the example below, the second field configuration displays a field labeled "Issue status". The third field, resolution, will display if the value of status is Completed and the resolution field has a value.

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
const formTemplate = new FormTemplate({
  title: "Inspector report",
  description: "Enter all relevant information below",
  elements: [
    new FieldElement({
      fieldName: "inspector",
      label: "Inspector name"
    }),
    new FieldElement({
      fieldName: "status",
      label: "Issue status"
    }),
    new FieldElement({
      fieldName: "resolution",
      label: "Resolution",
      // expression defined below
      visibilityExpression: "resolutionVisible"
    })
  ],
  expressionInfos: [{
    name: "resolutionVisible",
    title: "Resolution if status is completed",
    expression: "$feature.status == 'Completed' && !IsEmpty($feature.resolution)"
  }]
});

Form Calculation

The Form Calculation profile is implemented in the FeatureForm widget, allowing you to calculate field values conditionally during editing workflows. You can access a feature's attributes with $feature, attributes in the original feature ($originalFeature), and the edit type ($editcontext.editType). The expression must return a Text, Number, or a Date value.

Expressions are defined in the expression property of an ExpressionInfo object. ExpressionInfos are set on the FormTemplate.expressionInfos property. To conditionally calculate the value of a form element based on other form inputs, you must reference the expression name in the valueExpression property of the FieldElement.

In the example below, the first field is calculated based on the geometry of the feature. The last field, FullName, will be calculated based on the values of InspectorFirst and InspectorLast.

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
const formTemplate = new FormTemplate({
  title: "Inspector report",
  description: "Enter all relevant information below",
  elements: [
    new FieldElement({
      fieldName: "Area",
      label: "Area (square meters)",
      // expression defined in expressionInfos
      valueExpression: "area"
    }),
    new FieldElement({
      fieldName: "InspectorFirst",
      label: "First Name"
    })
    new FieldElement({
      fieldName: "InspectorLast",
      label: "Last Name"
    })
    new FieldElement({
      fieldName: "FullName",
      label: "Full Name",
      // expression defined in expressionInfos
      valueExpression: "fullName"
    }),
  ],
  expressionInfos: [{
    name: "area",
    title: "Area (square meters)",
    expression: "Round(AreaGeodetic($feature, 'square-meters'), 2)"
  }, {
    name: "fullName",
    title: "Inspector full name",
    expression: `
      IIF(!IsEmpty($feature.InspectorFirst) && !IsEmpty($feature.InspectorLast)){
        return $feature.InspectorFirst + " " + $feature.InspectorLast;
      }
    `
  }]
});

Feature sorting

In 2D MapViews you can use an Arcade expression to determine the sort order in which features should render in the view. Feature sorting is configured on the orderBy property of the FeatureLayer. Expressions for sorting feature drawing order must follow the Feature Z profile specification. They can reference attributes using $feature and must return a number or a date value.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
// Orders features by storm warning duration in descending order.
// Warnings with longer durations will be
// rendered on top of warnings with shorter durations.
layer.orderBy = [{
  valueExpression: "DateDiff($feature.Watch_End, $feature.Watch_Start, 'hours' )",
  order: "descending"
}];

Z values

In 3D SceneViews you can use Arcade expressions to set custom Z values on features. Although features can have Z values inside their geometry, you might want to calculate or replace them based on an attribute value, or derive it from a formula using the Z value. You may also have features that don't contain Z values in their geometries, but have Z-related information stored in an attribute field. In these cases you can set an expression in the featureExpressionInfo.expression property. Expressions for overriding Z values must follow the Feature Z profile specification. They can reference attributes using $feature and must return a number. As an example, the Elevation options sample shows how to change the Z value of points using Arcade:

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
layer.elevationInfo = {
  mode: "absolute-height",
  featureExpressionInfo: {
    expression: "Geometry($feature).z + $feature.HEIGHT"
  },
  unit: "meters"
};

In the example above, a field attribute HEIGHT is added to the Z value of the geometry to set the final graphic's elevation. For polyline or polygon features, all the vertices of each feature will use the same Z value returned fromexpression.

Image preview of related sample Create a custom visualization using Arcade

Create a custom visualization using Arcade

Create a custom visualization using Arcade

Image preview of related sample Reference Arcade expressions in PopupTemplate

Reference Arcade expressions in PopupTemplate

Reference Arcade expressions in PopupTemplate

Image preview of related sample Summarize intersecting points in a popup

Summarize intersecting points in a popup

Summarize intersecting points in a popup

Image preview of related sample Clustering - filter popup features

Clustering - filter popup features

This sample demonstrates how to filter clustered features within a cluster's popup.

Image preview of related sample Multi-line labels

Multi-line labels

Multi-line labels

Image preview of related sample Gridded proportional symbols

Gridded proportional symbols

Use primitive overrides to adjust CIMSymbol properties based on an attribute value

Arcade-driven visualizations

Use Arcade to dynamically calculate new data values as the basis for a visualization

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