Arcade is a lightweight and secure expression language written for use with ArcGIS. Like other expression languages, it can perform mathematical calculations and evaluate logical statements. It was designed specifically for creating custom visualizations and labeling expressions with ArcGIS, allowing users to write, share, and execute custom expressions in ArcGIS Pro, ArcGIS Online, the ArcGIS Runtime APIs, and the ArcGIS API for JavaScript.
What makes Arcade particularly unique to other expression and scripting languages is its inclusion of geometry functions. In the initial release of Arcade, geometries can be created and referenced. In future releases, other geometry functions may be added allowing you to calculate areas and lengths, and perform simple overlay operations in more complex 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 more details on how to write an Arcade expression. You also have access to a playground that provides an environment for testing custom scripts based on your data.
The power of Arcade is manifest in gaining access to global variables. Global variables contain external values that are passed to a script during its execution – based on the execution profile.
The $feature
global variable allows you to access field values for features in a FeatureLayer. Each field value is also considered a global variable. Field values are referenced using the following syntax:
$feature.fieldName
This makes it easy to perform simple calculations using field values at runtime.
// calculates the % of voters who voted for a
// democratic candidate
($feature.DEM_VOTES / $feature.TURNOUT ) * 100
Arcade is only executed within the context, or profile, in which it is understood. Within JavaScript apps, Arcade expressions are always referenced as a string value. You may use Arcade to write simple single-line expressions, or more complex multi-line epxressions.
When writing single-line expressions, you can simply wrap it in double or single quotes.
renderer.valueExpression = "Round( ($feature.AGE_18UP / $feature.TOTAL_POP) * 100 )";
When writing multi-line expressions, we recommend you place it in a separate script
tag outside the JavaScript portion of the app, and set the type to text/plain
with a unique ID you can use to reference the script in the appropriate place within JavaScript.
<script type="text/plain" id="adult-population">
// place multi-line Arcade expression here
</script>
Then you can reference the script as a string value by calling the document.getElementById()
method.
renderer.valueExpression = document.getElementById("adult-population").text;
See the example snippets below and the Create a renderer using Arcade sample sample for more context.
Arcade was designed for use in several profiles. A profile is a context in which the expression is understood and used. In the ArcGIS API 3.46 for JavaScript, Arcade supports three profiles: visualization, labeling, and popups
In the visualization profile, Arcade allows you to calculate values for each feature in a FeatureLayer at runtime and use those values as the basis for a data-driven visualization. This is an alternative approach to creating data-driven visualizations based on a single field value in the layer. To accomplish this, an Arcade expression may be passed to the valueExpression
property in ClassBreaksRenderer, UniqueValueRenderer or any of the visual variables: color, size, opacity, and rotation instead of referencing a field
/normalizationField
or a JavaScript function.
Arcade supports creating visualizations for FeatureLayer only. Other layer types that accept ClassBreaksRenderer and UniqueValueRenderer, such as ArcGISDynamicMapServiceLayer, do not support Arcade.
When used in a ClassBreaksRenderer or any of the visual variables, the expression must evaluate to a number. Expressions may evaluate to either strings or numbers in UniqueValueRenderer.
In the example below, an Arcade expression is used in the valueExpression property of a UniqueValueRenderer. In this case, we are creating a visualization for a FeatureLayer representing U.S. counties. The service has three fields that identify the number of republicans, democrats, and independent/non-party voters in each county. We would like to visualize each county based on which party outnumbers the others. Since the service does not contain a field indicating the predominant party, we can write an Arcade expression to identify that for each feature.
First, write the Arcade expression in a script tag with a unique ID.
<script type="text/plain" id="winning-party">
// 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' );
</script>
Then reference the script as a string value using document.getElementById()
within the appropriate valueExpression
property in the JavaScript.
// 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.
var winnerArcade = document.getElementById("winning-party").text;
var 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.
<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.
// 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.
var strengthArcade = document.getElementById("strength").text;
var opacityVV = {
type: "opacityInfo",
valueExpression: strengthArcade,
stops: [
{ value: 33, opacity: 0.1 },
{ value: 50, opacity: 1.0 }
]
};
// Add the visual variable to the renderer
renderer.setVisualVariables([ opacityVV ]);
Note that if Arcade expressions are set on a layer's renderer after it loads, the fields referenced in the expression must be manually included in the layer's outFields. However, if a renderer uses an Arcade expression and is set within a layer's constructor, then the fields referenced in the expression are automatically included in a layer's outFields.
View the Create a renderer using Arcade sample to see this example in context.
Arcade may also be used to create label expressions for features in a FeatureLayer. Starting at version 3.19 of the API, this is the only supported method for labeling features.
As is the case with labeling in previous versions of the API, you must add at least one LabelClass to the labelingInfo property of the FeatureLayer and set the showLabels
constructor parameter of Map to true. The Arcade expression must be passed as a string value to the expression property of the LabelClass's labelExpressionInfo object.
// returns the value of a field in the layer
// the value of this field will be the label for each feature
var arcade = "$feature.STATION_NAME";
// set the arcade expression to the `expression` property of labelExpressionInfo
var labelClass = new LabelClass({
labelExpressionInfo: {
expression: arcade
},
labelPlacement: "below-right",
minScale: 2500000
});
nameClass.symbol = new TextSymbol();
// set the label class to the feature layer
featureLayer.setLabelingInfo([ labelClass ]);
Label expressions written in Arcade may be more complex, containing multiple lines that perform mathematical and logical operations. For example, the Label features using Arcade expressions sample contains four different Arcade expressions with various levels of complexity. One of them simply returns a field value as demonstrated in the example snippet above. Two others return field values with additional text appended.
// returns the value of the TEMP field and concatenates it with the temperature units
// the value of TEMP is a number that is implicitly converted to a string
$feature.TEMP + '° F';
Finally, another expression used in the sample (shown below) demonstrates a more complex multi-line label expression. This expression assigns two numeric field values to their own variables and evaluates them to return a string value. Arcade's When() function is used to evaluate the wind direction (between 0-360 degrees) and return 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.
<script type="text/plain" id="wind-direction">
var DEG = $feature.WIND_DIRECT;
var SPEED = $feature.WIND_SPEED;
var DIR = When( SPEED == 0, null,
(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', null );
var WIND = SPEED + ' mph ' + DIR;
return WIND;
</script>
There are many additional functions useful for labeling, inluding 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. Also, be sure to take advantage of the Arcade playground. This app allows you to build, debug, and test an Arcade expression within a browser based on field values imported from an input feature service. It also includes the ability to debug complex scripts with a Console function.
Note that field names referenced in Arcade expressions within a layer's labelingInfo must be manually included in the layer's outFields.
Arcade expressions can also be referenced within the description of a PopupTemplate. Similar to the visualization profile, this is useful for situations when you want to display data that isn't present as an attribute value in your FeatureLayer instance.
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.
// labor force participation rate
Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)
The values returned from this expression can be used to visualize the layer and/or displayed in the layer's infoTemplate. To view the value in the popup, we must reference it in the expressionInfos
property of the PopupTemplate's constructor and assign it a name and a title.
layer.setInfoTemplate(new PopupTemplate({
expressionInfos: [{
name: "participation-rate",
title: "% of population 16+ participating in the labor force",
expression: "Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)"
}],
description: "In {NAME} county, {expression/participation-rate}% of the population"
+ " participates in the labor force."
}));
Notice that once the expression exists in the expressionInfos property of the object, you can reference the value returned from the expression using the {expession/expression-name} placeholder template within the description of the PopupTemplate. This results in the Popup's content displaying the following:
You can also reference values returned from Arcade expressions inside the fieldInfos property of the PopupTemplate to format the value. Just reference the name of the expression in the fieldName property of the object. Remember to use the expression/expression-name syntax.
layer.setInfoTemplate(new PopupTemplate({
expressionInfos: [{
name: "participation-rate",
title: "% of population 16+ participating in the labor force",
expression: "Round(($feature.CIVLBFR_CY / $feature.POP_16UP)*100,2)"
}],
fieldInfos: [{
fieldName: "expression/participation-rate",
format: {
places: 2
}
}]
}));
View the Reference Arcade expressions in PopupTemplate sample to see this workflow in the context of a live sample application.