Every card in a spaciv visualisation shows a number, a bar, a percentage, something calculated from your portfolio data. The function is what defines that calculation. Once you understand how functions work, you can read any card in the platform and know exactly where its numbers come from, and start building your own.
A function tells spaciv two things: which objects to look at, and what to calculate from them. Every function is built from one or more building blocks called sumof terms, combined with basic math.
A single sumof term looks like this:
sumof("Object Type" is "Space", "Area")
This says: look at all objects where the Object Type is Space, then sum up their Area. The result is the total floor area of every space in the current context.
Every sumof term has two parts, separated by a comma:
The selection decides which objects are included. The operation is the calculation run across them. It's usually a single property, but it can also be a small formula, such as multiplying two properties together:
sumof("Object Type" is "Space", "Area" * "Count")
This multiplies each space's Area by its Count before summing the results, useful when a single row represents more than one identical object.
A function is rarely the only thing filtering your data. By the time a number reaches a card, several layers of context have already been applied on top of the function itself:
The function is evaluated last, within all of that context. This is why the same function can show different numbers on different dashboards, or different cards, even though the underlying calculation never changed. If a number ever looks unexpected, it's worth checking these layers before assuming the function itself is wrong.
Take sumof("Object Type" is "Space", "Area" * "Count"). This sums the total area of all spaces if and only if the filters of this visualisation, or the segmentation, don't constrain it further. If you segment by Country in your card, then the data you're aggregating is partial, which means you are filtering for Country is "UK" AND Object Type is "Space", for the UK value. The function itself hasn't changed, but what it's summing has been narrowed by the the segmenting which is applied in the card.
A function isn't limited to a single sumof. It's really just a math expression, and sumof terms are one kind of value you can use inside it, alongside plain numbers and variables. That makes the pattern quite flexible:
A function can be pure math with no sumof at all, a constant added to a single sumof, or several sumof terms combined together, each with its own selection and operation, joined by normal operators like +, -, *, and /.
The most common reason to combine two sumof terms is to calculate an average:
sumof("Object Type" is "Space", "Area") / sumof("Object Type" is "Space", "Count")
Here, the total area is divided by the total count, giving the average area per space. Each sumof runs its own filter and calculation independently, so the two terms don't need to share the same selection, though in this example they do.
Functions can reference variables by name, using dollar signs around the variable name, for example $Occupancy Target$. This is especially useful for two situations:
Imagine a dataset of eight objects: five spaces and three consumers (people or equipment assigned to a space). Each space has an Area property.
sumof("Object Type" is "Space", "Area") adds up the Area of the five spaces: 20 + 25 + 30 + 15 + 10 = 100.sumof("Object Type" is "Space", "Count") counts the five space objects: 5.Change the selection to "Object Type" is "Consumer" and the same math now describes consumers instead, without touching the underlying data at all. This is the core idea behind functions: the same building blocks can answer very different questions, just by changing what you select.
When you segment a visualisation, for example by Attendance (what percentage of people is in/out of office), you sometimes want to visualise each segment in the context, like calculating the segment's proportional size. In the function, the segment keyword can be used to control which calculations are run on the segment (e.g. users in office) from those that are run on the entire dataset (all users).
Example
You're segmenting a card by Attendance, so each segment represents one attendance status (in office, out of office).
sumof("Object Type" is "Consumer", "Count" * segment) / sumof("Object Type" is "Consumer", "Count")
The numerator uses segment, so it only counts people within the current segment, for example just the "In Office" group. The denominator leaves segment out, so it counts everyone, across all attendance statuses. Dividing the two gives the percentage of people in the specific segment out of the total, the small percentage over the big one. The function runs twice, as we have two segments. Both results are presented in one visualization.
It's worth including certain properties in your functions early, even if they have no effect yet, because they tend to become relevant later. Count and Growth are good examples: they might not matter for your first few visualisations, but they come up often enough that it's easier to build them into functions from the start than to retrofit them afterward. The same logic applies to Enterprise accounts working with costs. As soon as a project starts dealing with currency, it's worth having a dedicated property such as Exchange Rate set up from the beginning, so it's already there to reference the moment you start calculating, rather than adding it in after the fact.
sumof terms with basic math, or none at all.sumof has a selection (what to filter) and an operation (what to calculate).sumof terms can be combined to build metrics like averages.$Variable Name$, are set at the project level (e.g. a fixed scenario or date) and let functions stay flexible across contexts.segment keyword lets a function calculate a value for just the current segment, alongside the same calculation across the whole dataset, useful for percentages and proportions.