DAX SVG measure · Trend
Power BI sparkline in a table with a DAX SVG measure
By Nawaf Sharaf · Founder & Reliability Engineer · Updated
Use it when
- You want trend shape per row (product, region, account) beside the current value.
- You need the latest-point dot, high/low markers or theme colours the built-in sparkline doesn't offer.
- You want the same trend picture inside a Card visual image, not just a table.
Skip it when
Readers need exact values for each period or have to compare levels between rows: each sparkline is scaled to its own min and max, so two identical shapes can hide very different numbers.
Three looks
The sparkline (line) in three palettes; click one to edit it.
Data it needs
The builder asks for exactly these fields; type your own measure and column names there.
- Value measure
- Any additive or non-additive measure, e.g. [Sales] or [Margin %]. It is evaluated once per axis value.
- Axis column
- A date or numeric column (e.g. 'Date'[Month Start]). It is converted to a number so gaps in time stay gaps.
- Row column
- Whatever is on the table's rows. It filters the series; it is not referenced in the measure.
The full DAX
Swap [Sales] and 'Date'[Month Start] for your own names.
Sparkline =
-- VizForge SVG measure: line sparkline.
-- Set Measure tools > Data category = Image URL. Put it in a table or matrix next to a category column.
-- The axis must be a date or number column so points are spaced in time order.
-- Made with the free VizForge SVG measure builder: vizforge.ai/tools/svg-measure-builder
-- Need per-point tooltips, click-to-select inside the chart or Format-pane settings? Generate it as a real custom visual: vizforge.ai/visuals
VAR _Base = FILTER (
ADDCOLUMNS (
ALLSELECTED ( 'Date'[Month Start] ),
"@x", CONVERT ( 'Date'[Month Start], DOUBLE ),
"@v", [Sales]
),
NOT ISBLANK ( [@v] )
)
VAR _XMin = MINX ( _Base, [@x] )
VAR _XMax = MAXX ( _Base, [@x] )
VAR _VMin = MINX ( _Base, [@v] )
VAR _VMax = MAXX ( _Base, [@v] )
VAR _Points = CONCATENATEX (
_Base,
FORMAT ( 3.5 + DIVIDE ( [@x] - _XMin, _XMax - _XMin, 0.5 ) * 113, "0.0", "en-US" )
& ","
& FORMAT ( 3.5 + ( 1 - DIVIDE ( [@v] - _VMin, _VMax - _VMin, 0.5 ) ) * 25, "0.0", "en-US" ),
" ",
[@x], ASC
)
RETURN
IF (
COUNTROWS ( _Base ) < 2,
BLANK (),
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='32' viewBox='0 0 120 32'><polyline fill='none' stroke='%23118DFF' stroke-width='1.5' stroke-linejoin='round' stroke-linecap='round' points='"
& _Points
& "'/><circle cx='"
& MAXX ( TOPN ( 1, _Base, [@x], DESC ), FORMAT ( 3.5 + DIVIDE ( [@x] - _XMin, _XMax - _XMin, 0.5 ) * 113, "0.0", "en-US" ) )
& "' cy='"
& MAXX ( TOPN ( 1, _Base, [@x], DESC ), FORMAT ( 3.5 + ( 1 - DIVIDE ( [@v] - _VMin, _VMax - _VMin, 0.5 ) ) * 25, "0.0", "en-US" ) )
& "' r='2.6' fill='%23118DFF'/></svg>"
)DAX user-defined function variant (VizForge.SvgSparkline)
One-line call: Sparkline = VizForge.SvgSparkline ( [Sales], 'Date'[Month Start] )
-- 1) Paste into DAX query view and choose 'Update model with changes'.
-- Needs DAX user-defined functions (generally available since the June 2026 Power BI release).
DEFINE
/// Sparkline (line) as an SVG image URL (VizForge). Optional parameters default to the colours you picked.
FUNCTION VizForge.SvgSparkline = (
pValue : ANYREF EXPR,
pAxis : ANYREF EXPR,
pLineColor : STRING = "#118DFF"
) =>
VAR _Base = FILTER (
ADDCOLUMNS (
ALLSELECTED ( pAxis ),
"@x", CONVERT ( pAxis, DOUBLE ),
"@v", CALCULATE ( pValue )
),
NOT ISBLANK ( [@v] )
)
VAR _XMin = MINX ( _Base, [@x] )
VAR _XMax = MAXX ( _Base, [@x] )
VAR _VMin = MINX ( _Base, [@v] )
VAR _VMax = MAXX ( _Base, [@v] )
VAR _Points = CONCATENATEX (
_Base,
FORMAT ( 3.5 + DIVIDE ( [@x] - _XMin, _XMax - _XMin, 0.5 ) * 113, "0.0", "en-US" )
& ","
& FORMAT ( 3.5 + ( 1 - DIVIDE ( [@v] - _VMin, _VMax - _VMin, 0.5 ) ) * 25, "0.0", "en-US" ),
" ",
[@x], ASC
)
RETURN
IF (
COUNTROWS ( _Base ) < 2,
BLANK (),
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='32' viewBox='0 0 120 32'><polyline fill='none' stroke='"
& SUBSTITUTE ( pLineColor, "#", "%23" )
& "' stroke-width='1.5' stroke-linejoin='round' stroke-linecap='round' points='"
& _Points
& "'/><circle cx='"
& MAXX ( TOPN ( 1, _Base, [@x], DESC ), FORMAT ( 3.5 + DIVIDE ( [@x] - _XMin, _XMax - _XMin, 0.5 ) * 113, "0.0", "en-US" ) )
& "' cy='"
& MAXX ( TOPN ( 1, _Base, [@x], DESC ), FORMAT ( 3.5 + ( 1 - DIVIDE ( [@v] - _VMin, _VMax - _VMin, 0.5 ) ) * 25, "0.0", "en-US" ) )
& "' r='2.6' fill='"
& SUBSTITUTE ( pLineColor, "#", "%23" )
& "'/></svg>"
)
EVALUATE { VizForge.SvgSparkline ( [Sales], 'Date'[Month Start] ) }
-- 2) Then create the measure and set Measure tools > Data category = Image URL:
-- Sparkline = VizForge.SvgSparkline ( [Sales], 'Date'[Month Start] )
-- Colours and thresholds are optional parameters: pass a value after the fields to override one.
-- Pass colours as plain "#RRGGBB"; the function encodes the # for the data URI.Placing it in a report
Put Product or Region on the table rows and the measure beside them, never 'Date'[Month Start] itself: a row that is already one month has one point and returns BLANK(). Image size 32 high by 120 wide keeps the line crisp. Remember the Image URL data category. All setup steps.
Gotchas
- Text month names ('Jan', 'Feb') can't be converted to numbers: use a month-start date column.
- The measure iterates ALLSELECTED over the axis, so a slicer on the axis column shortens the line; a slicer on another table does not.
- Rows with fewer than two non-blank points return BLANK() instead of a single dot.
- Length. 405 characters at 12 periods, 646 at 36, once per row.
- Context. Each row's product or region filter reaches every month through context transition, so [Sales] inside ADDCOLUMNS is that row's monthly sales. The total row gets the line for everything combined, scaled to its own min and max.
- Tooltip. Hovering shows the SVG text; a blank report-page tooltip hides it.
When an SVG measure isn't enough
An interactive sparkline shows the value of each point on hover and filters the page when a row is clicked. See the KPI card custom visual for what an interactive version can do.