---
title: "Calculator formula syntax"
description: "Every operator, function, and formatting method you can use in a popup equation, with the rules for attribute names and blank results."
---

Look up any operator, function, or formatting method here before you type it into an equation. This page covers Custom popup equations and Calculator popup Step 3, which use the same syntax.

Type every formula on this page in the equation editor, which opens when you click `Insert equation`. A formula typed straight into the popup text does not calculate.

## Numbers only

An equation takes numbers and gives one number. It cannot show text.

- Every attribute value is read as a number.
- The result must be a number. A formula that gives text or true/false stays blank.
- Each branch of a condition must give a number. `if({stock} > 0, {price}, 'Sold out')` shows the price when `stock` is above zero, but is blank for every other feature.

To show text that depends on an attribute, such as `Sold out`, use [conditional content](/docs/configuring-popups/add-conditional-content-to-popup), not an equation.

## Variable syntax

|         |                                                          |
| ------- | -------------------------------------------------------- |
| Syntax  | `{field_name}` |

Refers to the value of a feature attribute. Wrap each attribute in its own braces: `{population} / {area}` works, but `{population / area}` does not. A name without braces, such as `area`, is not read as an attribute, and the equation stays blank. The attribute name is the field's underlying name (not the alias from the Format tab).

Every attribute value is read as a number. A text value, such as `Bay`, makes the equation blank. So does an attribute that is missing or blank on the feature.

### Any attribute name works

Names with spaces or other characters, such as `{land value}`, work.

## Operators

Operators run in this order, first to last. Use parentheses to change the order.

| Operator | Meaning | Example | Result for the example |
| --- | --- | --- | --- |
| `( )` | Group | `({a} + {b}) / 2` | Average of `a` and `b` |
| `!` | Factorial | `{n}!` | `6` when `n` is `3` |
| `^` | Power | `{side} ^ 2` | `9` when `side` is `3` |
| `-` (before a value) | Negative | `-{change}` | `-4` when `change` is `4` |
| `+` (before a value) | No change | `+{a}` | Same as `{a}` |
| `*` | Multiply | `{rate} * {total}` | |
| `/` | Divide | `{total} / {households}` | |
| `%` | Remainder after dividing | `{total} % {per_box}` | `2` when `total` is `17` and `per_box` is `5` |
| `+` | Add | `{male} + {female}` | |
| `-` | Subtract | `{total} - {male}` | |
| `==`, `!=` | Equal, not equal | `{code} == 3 ? 1 : 0` | `1` when `code` is `3` |
| `<`, `<=`, `>`, `>=` | Less than, at most, more than, at least | `{a} > {b} ? {a} : {b}` | The larger value |
| `in` | Is in a list | `{code} in [1, 2, 3] ? 1 : 0` | `1` when `code` is `2` |
| `and` | Both are true | `{a} > 0 and {b} > 0 ? 1 : 0` | |
| `or` | One or both are true | `{a} > 0 or {b} > 0 ? 1 : 0` | |
| `not` | Is not true | `not ({a} > 0) ? 1 : 0` | |
| `? :` | If, then, else | `{stock} > 0 ? {price} : 0` | `price` when `stock` is above zero, else `0` |

The `×`, `÷`, and `−` symbols also work, and mean `*`, `/`, and `-`.

A comparison (`==`, `>`, `in`, `and`, and the others) gives true or false, not a number. Use it inside `? :` or `if(...)`, or the equation stays blank.

## Functions

Function names are case-sensitive: `round`, not `Round`. Put the arguments in parentheses, separated by commas.

### Rounding

| Function | Result | Example | Result for the example |
| --- | --- | --- | --- |
| `round(x)` | `x` rounded to the nearest whole number | `round(2.5)` | `3` |
| `roundTo(x, n)` | `x` rounded to `n` decimal places | `roundTo(98.76, 1)` | `98.8` |
| `floor(x)` | `x` rounded down | `floor(2.9)` | `2` |
| `ceil(x)` | `x` rounded up | `ceil(2.1)` | `3` |
| `trunc(x)` | `x` with its decimals removed | `trunc(-3.7)` | `-3` |

`round`, `roundTo`, `floor`, `ceil`, and `trunc` change the value. `Decimal Places` changes only how many decimals show.

### Sign, smallest, and largest

| Function | Result | Example | Result for the example |
| --- | --- | --- | --- |
| `abs(x)` | `x` without its negative sign | `abs(-3.7)` | `3.7` |
| `sign(x)` | `-1`, `0`, or `1`, for a negative value, zero, or a positive value | `sign(-3.7)` | `-1` |
| `min(a, b, ...)` | The smallest value | `min({this_year}, {last_year})` | |
| `max(a, b, ...)` | The largest value | `max({this_year}, {last_year})` | |

### Powers and roots

| Function | Result | Example | Result for the example |
| --- | --- | --- | --- |
| `sqrt(x)` | Square root. Blank if `x` is negative. | `sqrt(9)` | `3` |
| `cbrt(x)` | Cube root | `cbrt(27)` | `3` |
| `pow(x, y)` | `x` to the power `y`, the same as `x ^ y` | `pow(3, 3)` | `27` |
| `hypot(a, b)` | Square root of `a² + b²`. `pyt(a, b)` is the same. | `hypot(3, 4)` | `5` |
| `fac(n)` | Factorial, the same as `n!` | `fac(5)` | `120` |
| `exp(x)` | `E` to the power `x` | `exp(1)` | `2.718...` |
| `expm1(x)` | `exp(x) - 1` | `expm1(0)` | `0` |

### Logarithms

| Function | Result | Example | Result for the example |
| --- | --- | --- | --- |
| `ln(x)` | Natural logarithm (base `E`) | `ln(E)` | `1` |
| `log(x)` | Natural logarithm (base `E`), the same as `ln`. Not base 10. | `log(E)` | `1` |
| `log10(x)` | Base-10 logarithm | `log10(1000)` | `3` |
| `log2(x)` | Base-2 logarithm | `log2(8)` | `3` |
| `log1p(x)` | `ln(1 + x)` | `log1p(0)` | `0` |

### Angles

Angles are in radians. To change degrees to radians, multiply by `PI / 180`.

| Function | Result |
| --- | --- |
| `sin(x)`, `cos(x)`, `tan(x)` | Sine, cosine, tangent |
| `asin(x)`, `acos(x)`, `atan(x)` | Inverse sine, cosine, tangent |
| `atan2(y, x)` | The angle from `(0, 0)` to the point `(x, y)` |
| `sinh(x)`, `cosh(x)`, `tanh(x)` | Hyperbolic sine, cosine, tangent |
| `asinh(x)`, `acosh(x)`, `atanh(x)` | Inverse hyperbolic sine, cosine, tangent |

Example: `sin({bearing} * PI / 180)` gives the sine of a bearing in degrees.

### Conditions

| Function | Result | Example |
| --- | --- | --- |
| `if(condition, a, b)` | `a` if the condition is true, else `b`. The same as `condition ? a : b`. | `if({stock} > 0, {price}, 0)` |

`a` and `b` must both be numbers. Text, such as `'Sold out'`, makes the equation blank for every feature that gets that branch. To show text, use [conditional content](/docs/configuring-popups/add-conditional-content-to-popup).

### Other

| Function | Result |
| --- | --- |
| `random(n)` | A random number from `0` up to (but not including) `n`. The number changes each time the popup opens. |

## Constants

| Constant | Value |
| --- | --- |
| `PI` | 3.14159... |
| `E` | 2.71828... |

Example: `PI * {radius} ^ 2` gives the area of a circle.

## Format the result

By default, the result shows with the number of decimals in `Decimal Places`, and with no thousand separators: `12508.28`. To format it another way, add a formatting method to the end of the formula.

### Decimal places

|         |                                                          |
| ------- | -------------------------------------------------------- |
| Default | `2` |
| Range   | 0–10 |
| Where   | `Decimal Places` field in the equation editor modal |

Sets the number of decimals in the result. Each equation has its own setting. A formatting method replaces this setting.

### `.toLocaleString()`

|         |                                                          |
| ------- | -------------------------------------------------------- |
| Syntax  | `(formula).toLocaleString()` or `(formula).toLocaleString('locale')` |
| Default | `en-US` |

Adds thousand separators, in the number style of a locale (a country or language code). The result shows up to 3 decimals, with no zeros at the end. To set the decimals, round inside the formula first, with `round(...)` or `roundTo(..., n)`. You can also add `.toFixed(n)`.

| Formula | Result |
| --- | --- |
| `round({population} / {area}).toLocaleString()` | `12,508` |
| `roundTo({population} / {area}, 1).toLocaleString()` | `12,508.3` |
| `({population} / {area}).toFixed(2).toLocaleString()` | `12,508.28` |
| `({a} + {b}).toLocaleString()` | `4,000.75` |
| `({a} + {b}).toLocaleString('en-GB')` | `4,000.75` |
| `({a} + {b}).toLocaleString('de-DE')` | `4.000,75` |
| `({a} + {b}).toLocaleString('fr-FR')` | `4 000,75` |
| `({population} * 10).toLocaleString('en-IN')` | `1,23,45,670` |

A locale code in the wrong form, such as `en_US`, makes the equation blank. A code in the right form that no locale uses, such as `xx-YY`, gives a default number style.

#### Locales and number scripts

The locale code sets the separators. A code that ends in `-u-nu-` and a script name also shows the digits in that script. These results are for the value `123456789.01`:

| Number style | Locale code | Result |
| --- | --- | --- |
| Comma separators, point decimal (UK, US) | `en-GB`, `en-US` | `123,456,789.01` |
| Space separators, comma decimal (France, Russia) | `fr-FR`, `ru-RU` | `123 456 789,01` |
| Point separators, comma decimal (Germany) | `de-DE` | `123.456.789,01` |
| Apostrophe separators (Switzerland) | `de-CH` | `123'456'789.01` |
| Lakh separators (India) | `en-IN` | `12,34,56,789.01` |
| Arabic digits | `ar-EG` | `١٢٣٬٤٥٦٬٧٨٩٫٠١` |
| Persian digits | `fa-AF` | `۱۲۳٬۴۵۶٬۷۸۹٫۰۱` |
| Thai digits | `th-TH-u-nu-thai` | `๑๒๓,๔๕๖,๗๘๙.๐๑` |
| Devanagari digits | `hi-u-nu-deva` | `१२,३४,५६,७८९.०१` |
| Chinese digits | `zh-Hans-CN-u-nu-hanidec` | `一二三,四五六,七八九.〇一` |
| Full-width digits | `ja-JP-u-nu-fullwide` | `１２３,４５６,７８９.０１` |

Other locale codes and scripts also work. For every script name, see the [list of numbering systems](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/supportedValuesOf#supported_numbering_system_types). A script shows correctly only if the viewer's device has a font for it.

Only the locale code can change. Currency, percent, and unit styles are not available.

Moving from v3? The v3 locale examples work in v4. Type them in the equation editor without `#{ }#`: `({attribute}).toLocaleString('th-TH-u-nu-thai')`. v4 shows up to 3 decimals, so `(24586 / 6548).toLocaleString('fr-FR')` shows `3,755`. Use `roundTo(..., 2)` for `3,75`.

### `.toFixed(n)`

|         |                                                          |
| ------- | -------------------------------------------------------- |
| Syntax  | `(formula).toFixed(n)` |
| Range   | 0–100 |

Shows exactly `n` decimals: `({pct} * 100).toFixed(1)` gives `45.7`, and `.toFixed(0)` gives a whole number. On its own, `.toFixed(n)` adds no thousand separators. Add `.toLocaleString()` as well to get them.

### Rules for formatting methods

- Put the method at the end of the formula. It formats the result of the whole formula. Parentheses around the formula, as in `({a} + {b}).toLocaleString()`, make this clear to the reader.
- You can use both methods, in either order. For the value `4000.5`, `.toFixed(2).toLocaleString()` and `.toLocaleString().toFixed(2)` both give `4,000.50`.

## Preview messages

The `Preview (with sample values)` panel in the equation editor calculates the formula the same way as the popup. It uses the values of one sample feature from the layer. When the formula fails, the panel text is red. Below it, the panel shows `A failed formula shows blank on the map.`

| Message | When it shows | Popup on the map |
| --- | --- | --- |
| `= <value>`, such as `= 12,508` | The formula gives a number for the sample feature | The result |
| `Field not found: {name}` | The layer has no attribute with that name, for example because of a spelling mistake | Blank |
| `No sample value for {name}` | The sample feature has no value for that attribute | Blank for a feature with no value, and the result for the others |
| `Not a number: name` | The sample feature has a text value for that attribute, such as `Bay` | Blank for a feature with a text value |
| `Result is not a number` | The formula gives true or false, or text, such as `{a} > 5`. `0 / 0` also gives this message. | Blank |
| `Division by zero` | The formula divides a number other than zero by zero | Blank |
| `Syntax error` | The formula has a missing parenthesis, a misspelled function, or a name without braces. A formatting method or locale code in the wrong form also gives this message. | Blank |

The preview checks one feature only. A condition with a text branch, such as `if({stock} > 0, {price}, 'Sold out')`, shows a number when the sample feature takes the number branch. The popup is blank for every feature that takes the text branch.

In a Calculator popup, a user input such as `{form_1}` has no sample value. A formula that uses one shows `No sample value for {form_1}`.

## Sample formulas

| Goal | Formula |
| --- | --- |
| Sum two attributes | `{revenue} + {costs}` |
| Compute a ratio, such as people per km² | `{population} / {area}` |
| Share of a total, as a percentage | `({part} / {total}) * 100` |
| Round a result | `round({population} / {area})` |
| Round a result, with thousand separators | `round({population} / {area}).toLocaleString()` |
| Square a value | `{side} ^ 2` |
| Remainder after dividing | `{total} % {per_box}` |
| Larger of two attributes | `max({this_year}, {last_year})` |
| A value only when a condition is true | `{stock} > 0 ? {price} : 0` |
| Change hectares to acres | `{hectares} * 2.47105` |
| Use a user input | `{area} * {form_1}` |
| Combine attributes with user input | `({form_1} - {area}) / {area} * 100` |

## Related

- [How to use operators and functions in equations](/docs/configuring-popups/use-operators-and-functions-in-equations) — worked examples for the operators and functions above.
- [Popup tab controls](/docs/configuring-popups/popup-reference)
- [How to build a calculator popup](/docs/configuring-popups/build-a-calculator-popup)
- [How to add a calculated value to a custom popup](/docs/configuring-popups/add-equations-to-popup)
- [Report templating syntax](/docs/map-extensions/report-templating-reference) — where the aggregate variable syntax (`{field:sum}`, etc.) lives.
