# 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.

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 (π * 3^{2}):

`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 3^{2}, 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 `stop`

s 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 `stop`

s. 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: