Skip to main content

Styling your layers

Work with expressions

In the Maps SDK, you can specify the value for any layout property, paint property, or filter as an expression. Expressions define how one or more feature property value or the current zoom level are combined using logical, mathematical, string, or color operations to produce the appropriate style property value or filter decision.

A property expression is any expression defined using a reference to feature property data. Property expressions allow the appearance of a feature to change with its properties. They can be used to visually differentiate types of features within the same layer or create data visualizations.

A camera expression is any expression defined using ['zoom']. Such expressions allow the appearance of a layer to change with the map’s zoom level. Zoom expressions can be used to create the illusion of depth and control data density.

There are countless ways to apply property expressions to your application, including:

  • Data-driven styling: Specify style rules based on one or more data attribute.
  • Arithmetic: Do arithmetic on source data, for example performing calculations to convert units.
  • Conditional logic: Use if-then logic, for example to decide exactly what text to display for a label based on which properties are available in the feature or even the length of the name.
  • String manipulation: Take control over label text with things like uppercase, lowercase, and title case transforms without having to edit, re-prepare and re-upload your data.
RELATED
Mapbox Style Specification: Expressions

An expression defines a formula for computing the value of the property using the operators described in this section.

Syntax

The Maps SDK expressions follow this format:

Exp(.expression_name) {
argument_0
argument_1
}

The expression_name is the expression operator, for example, you would use product to multiply two arguments or switchCase to create conditional logic.

The arguments are either literal (numbers, strings, or boolean values) or else themselves expressions. The number of arguments varies based on the expression.

Here's one example using an expression to calculate an arithmetic expression (π * 32):

Exp(.product) {
Exp(.pi)
Exp(.power) {
3
2
}
}

This example uses the product operator to multiply two arguments. The first argument is pi, which is an expression that returns the mathematical constant pi. The second argument is another expression: a pow expression with two arguments of its own. It will return 32, and the result will be multiplied by π.

Expression types

  • Mathematical operators for performing arithmetic and other operations on numeric values
  • Logical operators for manipulating boolean values and making conditional decisions
  • String operators for manipulating strings
  • Data operators for providing access to the properties of source features
  • Camera operators for providing access to the parameters defining the current map view

Data-driven styling at runtime

You can use expressions to determine the style of features in a layer based on data properties in the source data. For example, if you have a source containing point data from individual responses to the 2010 U.S. Census and each point has an "ethnicity" data property, you can use expressions to specify the color of each circle based on reported ethnicity.

The example below uses the match operator to compare the value of the "ethnicity" data property for each point in the source to several possible values. The first argument of the match expression is the value of the "ethnicity" data property. There are several arguments that specify what to do if the value of the data property matches a given string and a final argument that specifies what to do if the value of the data property does not match any of the strings provided.

To read the values of the "ethnicity" data property, this example uses the get operator with "ethnicity" as the sole argument.

Then, it uses stops for the next several arguments for the match expression. Each stop has two arguments: the first is the value to compare to the value of the "ethnicity" data property and the second is the value that should be applied to the layer's circleColor property if the value of the data property matches the first argument.

The second argument of the stop is a color, which is constructed using the rgb operator.

The final argument of the match expression is a fallback value that should be applied to circleColor if the value of the "ethnicity" data property does not match any of the strings provided.

// Compare value of the "ethnicity" data property
// to several possible values
let circleColorExpression = Exp(.match) {
// Read the value of the "ethnicity" data property
Exp(.get) { "ethnicity" }
// If the value of the data property
// matches "White", then apply this color
"White"
UIColor.orange
"Black"
// If the value of the data property
// matches "Black", then apply this color
UIColor.blue
// If the value of the data property
// matches "Hispanic", then apply this color
"Hispanic"
UIColor.red
// If the value of the data property
// matches "Asian", then apply this color
"Asian"
UIColor.purple
// If the value of the "ethnicity" property does
// not match any of the above strings, use this color
UIColor.black
}

For more examples of expressions for data-driven styling, see the Maps SDK test application on GitHub.

Zoom-driven styling at runtime

You can use expressions to determine the style of features in a layer based on the camera position, including the zoom level. For example, if you have dense point data displayed using a circle layer, you may want to adjust the radius of circles based on the zoom level to make the data more readable at low zoom levels.

The example below uses the interpolate operator to produce a continuous, smooth series of values between pairs of input and output values ("stops"). Its first argument sets the interpolation type, the second is the value of the zoom level, and the remaining arguments specify the size of the circle radius that should be applied based on the value of the zoom level.

"Exponential" is one of a few types of interpolation available Mapbox expressions. An expression using the exponential operator has one argument: the base, which controls the rate at which the output increases.

The zoom expression does not require any arguments. It will return the value of the current zoom level of the map.

The remaining arguments of the interpolate expression are stops. They represent points along the exponential curve. When a user is viewing the map at zoom level 12 or below, the circles will have a radius of 2. When viewing it at zoom level 22 and above, the circles will have a radius of 180. For all zoom levels between, the radius will be determined by an exponential function and the value will fall somewhere between 2 and 180.

var populationLayer = CircleLayer(id: "population", source: "ethnicity-source")
populationLayer.sourceLayer = "sf2010"

let stops: [Double: Double] = [
// If the map is at zoom level 12 or below,
// set circle radius to 2
12: 2.0,
// If the map is at zoom level 22 or above,
// set circle radius to 180
22: 180.0
]

// Produce a continuous, smooth series of values
// between pairs of input and output values
let zoomExp = Exp(.interpolate) {
// Set the interpolation type
Exp(.exponential) { 1.75 }
// Get current zoom level
Exp(.zoom)
// Use the stops defined above
stops
}

populationLayer.circleRadius = .expression(zoomExp)

For more examples of expressions for zoom-driven styling, see the Maps SDK test application on GitHub.

Light-driven styling in Standard and Standard Satellite

Mapbox Standard and Standard Satellite uses 3D lighting which affects the entire map, like lighting in the real world. This means that when you switch to dark lights, for example to the “night” preset, your custom layers will also be dark. If you want to change how light affects your custom layer, you will need to configure *-emissive-strength, a property which controls how light is being emitted. *-emissive-strength applies to background, fill, circle, text and line layer types.

Here’s an example how you would set *-emissive-strength for a line layer:

var layer = LineLayer(id: "my-line-layer", source: "vector-source")
layer.sourceLayer = "road"
layer.lineEmissiveStrength = .constant(1)
layer.slot = "middle"
var source = VectorSource(id: "vector-source")
source.url = "mapbox://mapbox.mapbox-streets-v8"
do {
try mapboxMap.addSource(source)
try mapboxMap.addLayer(layer)
} catch let error {
print("Error adding source: \(error)")
}

This image illustrates how different line-emissive-strength values are impacting the visual appearance of a line layer:

Was this page helpful?