Metric Transforms
Apply analytical window functions like running totals, moving averages, and period-over-period comparisons to your metrics
Overview
Metric transforms apply analytical window functions to your metrics in the Explorer. They take already-aggregated values (like SUM(Revenue)) and compute running totals, moving averages, period deltas, or percent-of-total calculations across rows.
Four transform types:
| Transform | What It Does | Typical Use Case |
|---|---|---|
| Running Total | Cumulative sum over an ordered sequence | Track how revenue accumulates month by month |
| Moving Average | Rolling average over N rows | Smooth out daily fluctuations to reveal trends |
| Previous Period Delta | Difference from the prior row | Show month-over-month revenue change |
| Percent of Total | Each row as a share of the total | See each region's contribution to overall revenue |
Transforms vs. Calculated Fields
Calculated fields create new derived metrics from raw data. Metric transforms apply analytical functions to existing, already-aggregated metrics. Use calculated fields to define what to measure. Use transforms to analyze how those measurements change across rows.
How It Works
Metric transforms operate as a second pass over your query results:
- Aggregation runs first -- your base query groups and aggregates data (e.g.,
SUM(Revenue) GROUP BY month) - The window function applies -- the transform wraps the aggregated metric in a SQL window function (e.g.,
SUM(metric) OVER (ORDER BY month)) - Results return -- you see both the original metric and the transformed values
This is why transforms require at least one group-by field. Without grouping, there are no rows to window over.
Getting Started
- Add a numeric metric to your visualization (e.g., SUM of Revenue)
- Click on the metric to expand its configuration
- Open the Metric Transform section
- Select a transform type from the dropdown
- Configure the parameters (order-by field, direction, window size, etc.)
Semaphor auto-detects the first date field in your group-by columns as the default Order By field. You can change this to any other group-by field.
Transform Types
Running Total
Computes a cumulative sum of the metric, row by row, in the order you specify.
Parameters:
| Parameter | Description | Default |
|---|---|---|
| Order By | Field that determines row sequence | First date field in group-by |
| Direction | Sort order (ascending or descending) | Ascending |
| Reset By | Fields that restart the cumulative sum | All group-by fields except Order By |
Example: Cumulative Revenue Over Time
Group by Order Date (month), metric: SUM(Revenue), transform: Running Total.
| Month | Revenue | Cumulative Revenue |
|---|---|---|
| Jan | $10,000 | $10,000 |
| Feb | $15,000 | $25,000 |
| Mar | $12,000 | $37,000 |
| Apr | $18,000 | $55,000 |
Each row adds the current month's revenue to the running total of all previous months.
Moving Average
Computes a rolling average over a sliding window of N rows.
Parameters:
| Parameter | Description | Default |
|---|---|---|
| Window Size | Number of rows in the rolling window | 7 |
| Min Periods | Minimum rows required before returning a value | 1 |
| Order By | Field that determines row sequence | First date field in group-by |
| Direction | Sort order (ascending or descending) | Ascending |
| Reset By | Fields that restart the window | All group-by fields except Order By |
Example: 7-Day Moving Average of Daily Sales
Group by Sale Date (day), metric: SUM(Sales), transform: Moving Average, window size: 7.
| Day | Daily Sales | 7-Day Moving Avg |
|---|---|---|
| Day 1 | $500 | $500 |
| Day 2 | $700 | $600 |
| Day 3 | $300 | $500 |
| Day 4 | $600 | $525 |
| Day 5 | $400 | $500 |
| Day 6 | $900 | $567 |
| Day 7 | $800 | $614 |
| Day 8 | $600 | $614 |
Early rows use fewer data points. Once the window fills (Day 7 onward), each value averages exactly 7 days.
Min Periods
Set Min Periods equal to your Window Size to avoid partial-window results at the start. With min periods set to 7, the first 6 rows would show no value instead of an average based on fewer than 7 data points.
Previous Period Delta
Computes the difference between the current row and the previous row. Available in two modes:
- Absolute -- raw difference (
current - previous) - Percent -- percentage change (
(current - previous) / previous)
Parameters:
| Parameter | Description | Default |
|---|---|---|
| Mode | Absolute (raw difference) or Percent (percentage change) | Absolute |
| Order By | Field that determines row sequence | First date field in group-by |
| Direction | Sort order (ascending or descending) | Ascending |
| Reset By | Fields that restart the comparison | All group-by fields except Order By |
Example: Month-over-Month Revenue Change
Group by Date (month), metric: SUM(Revenue), transform: Previous Period Delta.
| Month | Revenue | Change (Absolute) | Change (Percent) |
|---|---|---|---|
| Jan | $10,000 | -- | -- |
| Feb | $15,000 | +$5,000 | +50.0% |
| Mar | $12,000 | -$3,000 | -20.0% |
| Apr | $18,000 | +$6,000 | +50.0% |
The first row has no previous value to compare against, so the delta is empty.
Percent of Total
Expresses each row's metric as a percentage (or fraction) of the total. Available in two scopes:
- Grand Total -- each row divided by the overall sum across all rows
- Partition Total -- each row divided by the sum within its partition group
Parameters:
| Parameter | Description | Default |
|---|---|---|
| Scope | Grand Total (all rows) or Partition Total (within partition group) | Grand Total |
| Output | Percent (0-100) or Fraction (0-1) | Percent |
| Reset By | Partition fields (only for Partition Total scope) | All group-by fields except Order By |
Example: Regional Revenue Contribution
Group by Region, metric: SUM(Revenue), transform: Percent of Total, scope: Grand Total.
| Region | Revenue | % of Total |
|---|---|---|
| North | $50,000 | 33.3% |
| South | $30,000 | 20.0% |
| East | $40,000 | 26.7% |
| West | $30,000 | 20.0% |
Partitioning (Reset By)
Partitioning controls when a window calculation resets. Without partitioning, the window spans all rows. With partitioning, it restarts for each distinct value of the partition fields.
Example: Running Total with Region Partitioning
Group by Region + Month, metric: SUM(Revenue), transform: Running Total, order by: Month, reset by: Region.
| Region | Month | Revenue | Cumulative (per Region) |
|---|---|---|---|
| North | Jan | $5,000 | $5,000 |
| North | Feb | $7,000 | $12,000 |
| North | Mar | $6,000 | $18,000 |
| South | Jan | $3,000 | $3,000 |
| South | Feb | $4,000 | $7,000 |
| South | Mar | $5,000 | $12,000 |
The cumulative sum resets to zero when the region changes. Without the Region partition, the running total would accumulate across all regions continuously.
By default, Semaphor uses all group-by fields except the order-by field as partitions. You can toggle individual fields on or off in the Reset By section.
Compatibility
Supported Chart Types
| Chart Type | Supported |
|---|---|
| Bar | Yes |
| Line | Yes |
| Area | Yes |
| Aggregate Table | Yes |
| Pivot Table | Yes |
| Detail Table | No |
| KPI | No |
Database Support
Metric transforms work with all supported database dialects: PostgreSQL, MySQL, BigQuery, Redshift, Snowflake, ClickHouse, DuckDB, and MSSQL.
Constraints
- The metric must be numeric (SUM, AVG, COUNT, MIN, MAX, or COUNT DISTINCT)
- At least one group-by field is required
- Metric transforms and metric comparisons cannot be used on the same metric simultaneously -- use one or the other
Best Practices
Choose appropriate order-by fields. Date fields are the most natural choice for time-series analysis. Running totals and moving averages over non-temporal fields can produce confusing results unless the ordering is meaningful.
Use partitioning to avoid misleading totals. A running total across unrelated categories (e.g., cumulating revenue across both "North" and "South" without partitioning) often produces numbers that are hard to interpret. Partition by the category to get per-group cumulations.
Match window size to data granularity. For moving averages, align the window to a meaningful period: 7 for daily data (weekly average), 4 for weekly data (monthly average), 12 for monthly data (yearly average).
Control partial-window behavior. Set min periods equal to window size if you want to suppress early rows where the moving average is based on fewer data points than intended.
Percent of total with partition scope. Use Partition Total when you want "percent within category" analysis (e.g., each product's share within its category). Use Grand Total when you want each row's share of the entire dataset.
Additional Resources
- Calculated Fields -- create derived metrics and dimensions
- Semantic Domains -- metric transforms work with domain fields
- Filters -- combine transforms with dashboard-level filtering