agentsclimarketplace

Measures

Skill jonathan-pap/PowerBI-Claude-Design/measures

Comprehensive guide to designing, naming, and implementing Power BI DAX measures across all business domains. Includes patterns for base aggregations, time intelligence, KPIs, semi-additive measures, and TMDL syntax for measure definitions in .tmdl files.From its SKILL.md

Install
npx -y skills add jonathan-pap/PowerBI-Claude-Design --skill measures

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.9 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it

Power BI DAX Measures — Design Studio Guide

This guide teaches how to scaffold a complete measure layer for any Power BI semantic model. Use this when a user describes their reporting needs to generate production-ready DAX expressions with proper naming, folder structure, and TMDL syntax.


1. Naming Conventions & Prefixes

All measures use prefixes to signal their type.

PrefixTypeExampleformatString
#Count / Distinct Count# Orders, # Customers#,0
$Currency$ Revenue, $ Cost"$#,0.00"
%Ratio / Percentage% Margin, % Growth"0.00%"
ΔVariance (Absolute)Δ Revenue, Δ Headcount"#,0" or "$#,0"
Δ%Variance (Percent)Δ% Revenue, Δ% Target"0.00%"
(none)Helper / DimensionDays in Period, Current Month Numvaries

Naming Principles

  • Verbose over cryptic: $ Revenue Net of Discounts beats $ Rev ND
  • Avoid abbreviations except standard business terms (YTD, QTD, MTD, PY)
  • Order variants left-to-right: base first, then comparisons
    • ✓ $ Revenue, $ Revenue PY, $ Revenue YTD
    • ✗ $ PY Revenue, $ YTD Revenue

2. Display Folder Structure

├── Key Metrics
│   ├── Revenue & Profitability
│   ├── Efficiency
│   └── Quality
├── Time Intelligence
│   ├── Year-to-Date
│   ├── Prior Year Comparisons
│   └── Period-over-Period
├── Budget vs Actual
│   ├── Actual Measures
│   ├── Budget Measures
│   └── Variance
├── Ratios & Rates
└── Drilling & Details
    └── Helper Calculations

Rules:

  • One or two levels deep — avoid deeper nesting
  • Align folders with report pages: a "Variance Analysis" page → Variance Analysis folder
  • Group by business metric, not by function (Key Metrics, not SUM Measures)

3. TMDL Wrapper

All generated TMDL uses createOrReplace targeting _measures. Measures sit at 2 TABs, properties at 3 TABs, multi-line DAX body at 4 TABs:

createOrReplace

	ref table _measures

		/// Description of the measure
		measure '$ Revenue' = SUM(Sales[Revenue])
			formatString: "$#,0.00"
			displayFolder: "Key Metrics\Revenue & Profitability"

The createOrReplace / ref table _measures header is omitted from the pattern examples below for brevity — always include it in generated output.


4. Base Measure Patterns

Pattern 1: Simple Sum / Count

DAX:

$ Revenue = SUM(Sales[Revenue])
# Orders = COUNTROWS(Sales)

TMDL:

		/// Total revenue from all sales transactions
		measure '$ Revenue' = SUM(Sales[Revenue])
			formatString: "$#,0.00"
			displayFolder: "Key Metrics\Revenue & Profitability"

		/// Number of sales orders
		measure '# Orders' = COUNTROWS(Sales)
			formatString: "#,0"
			displayFolder: "Key Metrics"

Pattern 2: SUMX for Row-Level Calculation

DAX:

$ Revenue = SUMX(Sales, Sales[Quantity] * Sales[Unit Price])

TMDL:

		measure '$ Revenue' =
				SUMX(Sales, Sales[Quantity] * Sales[Unit Price])
			formatString: "$#,0.00"
			displayFolder: "Key Metrics\Revenue & Profitability"

Pattern 3: Conditional Aggregation with CALCULATE + FILTER

DAX:

# High-Value Orders =
CALCULATE(
    COUNTROWS(Sales),
    Sales[Revenue] > 1000
)

TMDL:

		measure '# High-Value Orders' =
				CALCULATE(
					COUNTROWS(Sales),
					Sales[Revenue] > 1000
				)
			formatString: "#,0"
			displayFolder: "Key Metrics"

Pattern 4: Distinct Count

DAX:

# Customers = DISTINCTCOUNT(Sales[CustomerID])

TMDL:

		measure '# Customers' = DISTINCTCOUNT(Sales[CustomerID])
			formatString: "#,0"
			displayFolder: "Key Metrics"

Pattern 5: Average / Rate with DIVIDE

DAX:

$ Average Order Value =
DIVIDE(
    SUM(Sales[Revenue]),
    DISTINCTCOUNT(Sales[OrderID]),
    0
)

TMDL:

		measure '$ Average Order Value' =
				DIVIDE(
					SUM(Sales[Revenue]),
					DISTINCTCOUNT(Sales[OrderID]),
					0
				)
			formatString: "$#,0.00"
			displayFolder: "Key Metrics\Efficiency"

5. Time Intelligence Patterns

Requires a marked Date table with a [Date] column and an active relationship to fact tables.

Pattern 1: Year-to-Date (YTD)

DAX:

$ Revenue YTD =
CALCULATE(
    [$ Revenue],
    DATESYTD(Date[Date])
)

TMDL:

		measure '$ Revenue YTD' =
				CALCULATE(
					[$ Revenue],
					DATESYTD(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Year-to-Date"

Pattern 2: Quarter-to-Date (QTD)

DAX:

$ Revenue QTD =
CALCULATE(
    [$ Revenue],
    DATESQTD(Date[Date])
)

TMDL:

		measure '$ Revenue QTD' =
				CALCULATE(
					[$ Revenue],
					DATESQTD(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Quarter-to-Date"

Pattern 3: Month-to-Date (MTD)

DAX:

$ Revenue MTD =
CALCULATE(
    [$ Revenue],
    DATESMTD(Date[Date])
)

TMDL:

		measure '$ Revenue MTD' =
				CALCULATE(
					[$ Revenue],
					DATESMTD(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Month-to-Date"

Pattern 4: Prior Year (PY)

DAX:

$ Revenue PY =
CALCULATE(
    [$ Revenue],
    SAMEPERIODLASTYEAR(Date[Date])
)

TMDL:

		measure '$ Revenue PY' =
				CALCULATE(
					[$ Revenue],
					SAMEPERIODLASTYEAR(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Prior Year Comparisons"

Pattern 5: Prior Year YTD

DAX:

$ Revenue PY YTD =
CALCULATE(
    [$ Revenue],
    SAMEPERIODLASTYEAR(DATESYTD(Date[Date]))
)

TMDL:

		measure '$ Revenue PY YTD' =
				CALCULATE(
					[$ Revenue],
					SAMEPERIODLASTYEAR(DATESYTD(Date[Date]))
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Prior Year Comparisons"

Pattern 6: Rolling N Months

DAX:

$ Revenue L12M =
CALCULATE(
    [$ Revenue],
    DATESINPERIOD(Date[Date], LASTDATE(Date[Date]), -12, MONTH)
)

TMDL:

		measure '$ Revenue L12M' =
				CALCULATE(
					[$ Revenue],
					DATESINPERIOD(Date[Date], LASTDATE(Date[Date]), -12, MONTH)
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Period-over-Period"

Use LASTDATE(Date[Date]) not TODAY() — LASTDATE respects the visual's date filter.


6. KPI Measures — Variance, Status, Targets

Pattern 1: Absolute Variance

DAX:

Δ Revenue vs Target = [$ Revenue] - [Target Revenue]

TMDL:

		measure 'Δ Revenue vs Target' = [$ Revenue] - [Target Revenue]
			formatString: "$#,0.00"
			displayFolder: "Budget vs Actual\Variance"

Pattern 2: Variance as Percentage

DAX:

Δ% Revenue vs Target =
DIVIDE(
    [$ Revenue] - [Target Revenue],
    [Target Revenue],
    0
)

TMDL:

		measure 'Δ% Revenue vs Target' =
				DIVIDE(
					[$ Revenue] - [Target Revenue],
					[Target Revenue],
					0
				)
			formatString: "0.00%"
			displayFolder: "Budget vs Actual\Variance"

Pattern 3: Status Flag (−1 / 0 / 1)

Returns 1 (above target), 0 (no data), −1 (below target) — drives conditional formatting or SVG icons.

DAX:

Status Revenue =
IF(
    ISBLANK([$ Revenue]),
    0,
    IF([$ Revenue] >= [Target Revenue], 1, -1)
)

TMDL:

		measure 'Status Revenue' =
				IF(
					ISBLANK([$ Revenue]),
					0,
					IF([$ Revenue] >= [Target Revenue], 1, -1)
				)
			formatString: "0"
			displayFolder: "Budget vs Actual"

Pattern 4: Target / Budget Measure

DAX:

Target Revenue = SUM(Budget[TargetRevenue])

TMDL:

		measure 'Target Revenue' = SUM(Budget[TargetRevenue])
			formatString: "$#,0.00"
			displayFolder: "Budget vs Actual\Budget Measures"

7. Semi-Additive Measures

Semi-additive measures must not be summed across time. Use LASTNONBLANK or LASTDATE.

Pattern 1: Period-End Balance (LASTNONBLANK)

Use case: Headcount, inventory, account balance at end of period.

DAX:

# Headcount EOP =
CALCULATE(
    SUM(Headcount[Employees]),
    LASTNONBLANK(Date[Date], CALCULATE(SUM(Headcount[Employees])))
)

TMDL:

		measure '# Headcount EOP' =
				CALCULATE(
					SUM(Headcount[Employees]),
					LASTNONBLANK(Date[Date], CALCULATE(SUM(Headcount[Employees])))
				)
			formatString: "#,0"
			displayFolder: "Key Metrics"

Pattern 2: Period-End Balance (LASTDATE)

DAX:

$ Account Balance EOD =
CALCULATE(
    SUM(GL[Balance]),
    LASTDATE(Date[Date])
)

TMDL:

		measure '$ Account Balance EOD' =
				CALCULATE(
					SUM(GL[Balance]),
					LASTDATE(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Key Metrics"

Pattern 3: Average of Semi-Additive

DAX:

$ Average Daily Balance =
AVERAGEX(
    VALUES(Date[Date]),
    [$ Account Balance EOD]
)

TMDL:

		measure '$ Average Daily Balance' =
				AVERAGEX(
					VALUES(Date[Date]),
					[$ Account Balance EOD]
				)
			formatString: "$#,0.00"
			displayFolder: "Key Metrics"

8. Error Handling

DIVIDE (preferred over /)

Always use DIVIDE(numerator, denominator, alternateResult) — returns alternateResult (default BLANK()) instead of an error when denominator is zero.

% Margin =
DIVIDE(
    SUM(Sales[Profit]),
    SUM(Sales[Revenue]),
    0
)

IFERROR

Catches any error in an expression:

% Utilization =
IFERROR(
    DIVIDE(SUM(Hours[Billable]), SUM(Hours[Total]), BLANK()),
    BLANK()
)

VAR + ISBLANK guard

Prevents downstream errors when a dependency measure is blank:

$ Revenue vs Target =
VAR _actual = [$ Revenue]
VAR _target = [Target Revenue]
RETURN
    IF(
        ISBLANK(_target),
        BLANK(),
        _actual - _target
    )

9. formatString Quick Reference

PatternDisplays asUse for
"$#,0.00"$1,234.56USD currency
"€#,0.00"€1,234.56EUR currency
"#,0"1,235Whole number counts
"0.0%"12.3%Percentages (1 decimal)
"0.00%"12.35%Percentages (2 decimal)
"#,0,,"M"1.2MCompact millions
"#,0,"K"1.2KCompact thousands

10. Measure Assembly — Requirements to TMDL

When a user describes reporting needs, follow this process:

Example: "Track quarterly sales with prior-year comparison and variance to quota."

Step 1 — Extract metrics:

  • $ Revenue — base sum
  • $ Revenue PY — prior year comparison
  • Target Quota — budget/target
  • Δ Revenue vs Quota — absolute variance
  • Δ% Revenue vs Quota — percent variance

Step 2 — Assign folders:

Key Metrics\Revenue & Profitability  → $ Revenue
Budget vs Actual\Budget Measures     → Target Quota
Budget vs Actual\Variance            → Δ Revenue vs Quota, Δ% Revenue vs Quota
Time Intelligence\Prior Year         → $ Revenue PY

Step 3 — Generate TMDL:

createOrReplace

	ref table _measures

		measure '$ Revenue' = SUM(Sales[Amount])
			formatString: "$#,0.00"
			displayFolder: "Key Metrics\Revenue & Profitability"

		measure 'Target Quota' = SUM(Budget[QuotaAmount])
			formatString: "$#,0.00"
			displayFolder: "Budget vs Actual\Budget Measures"

		measure '$ Revenue PY' =
				CALCULATE(
					[$ Revenue],
					SAMEPERIODLASTYEAR(Date[Date])
				)
			formatString: "$#,0.00"
			displayFolder: "Time Intelligence\Prior Year Comparisons"

		measure 'Δ Revenue vs Quota' = [$ Revenue] - [Target Quota]
			formatString: "$#,0.00"
			displayFolder: "Budget vs Actual\Variance"

		measure 'Δ% Revenue vs Quota' =
				DIVIDE([Δ Revenue vs Quota], [Target Quota], 0)
			formatString: "0.00%"
			displayFolder: "Budget vs Actual\Variance"

11. Key Properties Reference

PropertyPurposeExample
formatStringDisplay format in visuals"$#,0.00", "0.00%", "#,0"
displayFolderGroup in Field List"Key Metrics\Revenue"
descriptionTooltip in Field List"Cumulative revenue YTD"
isHiddenHide from Field ListisHidden (for helper measures)

Related References

  • tmdl-standards/SKILL.md — TMDL syntax ground rules: indentation, createOrReplace wrapper, property order
  • calc-groups/SKILL.md — When to replace individual Time Intelligence measures with a calc group
  • dax-udf/SKILL.md — When to extract repeated measure logic into a reusable typed function
  • svg-measures/SKILL.md — Wrapping scalar measure output in SVG strings for visual KPI display

Version: 2.0 Last Updated: 2026-05-02

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.