DAX SVG measure · Trend

Win/loss sparkline in Power BI with a DAX SVG measure

A win/loss chart throws away magnitude on purpose. Every period is either above zero (a win), below zero (a loss) or exactly zero (a tie), drawn as identical ticks, so the eye reads streaks: three missed SLA weeks in a row, a run of beaten targets.

By · Founder & Reliability Engineer · Updated

Win/loss bars rendered from the DAX below with sample data
Rendered from the measure below with sample data at 2× (120×24 px in Power BI). 912 characters.

Use it when

  • The question is 'how often' and 'in a row', not 'by how much'.
  • You track pass/fail per period: SLA met, budget held, forecast beaten.

Skip it when

The size of the miss matters for decisions: a 0.1% miss and a 40% miss look identical here. Add a variance bar column next to it.

Three looks

The win/loss bars 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.

Signed measure
Positive = win, negative = loss, zero = tie. Usually [Actual] − [Target] or a 1/−1 flag measure.
Axis column
Date or numeric period column.

The full DAX

Swap [Sales vs Target] and 'Date'[Month Start] for your own names.

Win Loss (measure)
Win Loss =
-- VizForge SVG measure: win/loss bars.
-- 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 vs Target]
    ),
    NOT ISBLANK ( [@v] )
)
VAR _Data = ADDCOLUMNS ( _Base, "@i", RANKX ( _Base, [@x], , ASC, DENSE ) )
VAR _Slot = DIVIDE ( 118, COUNTROWS ( _Data ), 0 )
VAR _Bars = CONCATENATEX (
    _Data,
    "<rect x='"
            & FORMAT ( 1 + ( [@i] - 1 ) * _Slot, "0.0", "en-US" )
            & "' y='"
            & IF (
                [@v] > 0,
                FORMAT ( 2, "0.0", "en-US" ),
                IF ( [@v] < 0, FORMAT ( 13, "0.0", "en-US" ), FORMAT ( 11, "0.0", "en-US" ) )
            )
            & "' width='"
            & FORMAT ( _Slot * 0.7, "0.0", "en-US" )
            & "' height='"
            & IF ( [@v] = 0, FORMAT ( 2, "0.0", "en-US" ), FORMAT ( 9, "0.0", "en-US" ) )
            & "' fill='"
            & IF ( [@v] > 0, "%231AAB40", IF ( [@v] < 0, "%23D64554", "%23605E5C" ) )
            & "'/>",
    "",
    [@i], ASC
)
RETURN
    IF (
        COUNTROWS ( _Data ) < 1,
        BLANK (),
        "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='24' viewBox='0 0 120 24'>"
            & _Bars
            & "</svg>"
    )
DAX user-defined function variant (VizForge.SvgWinLoss)

One-line call: Win Loss = VizForge.SvgWinLoss ( [Sales vs Target], 'Date'[Month Start] )

DAX query view script
-- 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
    /// Win/loss bars as an SVG image URL (VizForge). Optional parameters default to the colours you picked.
    FUNCTION VizForge.SvgWinLoss = (
            pValue : ANYREF EXPR,
            pAxis : ANYREF EXPR,
            pWinColor : STRING = "#1AAB40",
            pLossColor : STRING = "#D64554",
            pTieColor : STRING = "#605E5C"
        ) =>
        VAR _Base = FILTER (
            ADDCOLUMNS (
                ALLSELECTED ( pAxis ),
                "@x", CONVERT ( pAxis, DOUBLE ),
                "@v", CALCULATE ( pValue )
            ),
            NOT ISBLANK ( [@v] )
        )
        VAR _Data = ADDCOLUMNS ( _Base, "@i", RANKX ( _Base, [@x], , ASC, DENSE ) )
        VAR _Slot = DIVIDE ( 118, COUNTROWS ( _Data ), 0 )
        VAR _Bars = CONCATENATEX (
            _Data,
            "<rect x='"
                    & FORMAT ( 1 + ( [@i] - 1 ) * _Slot, "0.0", "en-US" )
                    & "' y='"
                    & IF (
                        [@v] > 0,
                        FORMAT ( 2, "0.0", "en-US" ),
                        IF ( [@v] < 0, FORMAT ( 13, "0.0", "en-US" ), FORMAT ( 11, "0.0", "en-US" ) )
                    )
                    & "' width='"
                    & FORMAT ( _Slot * 0.7, "0.0", "en-US" )
                    & "' height='"
                    & IF ( [@v] = 0, FORMAT ( 2, "0.0", "en-US" ), FORMAT ( 9, "0.0", "en-US" ) )
                    & "' fill='"
                    & IF (
                        [@v] > 0,
                        SUBSTITUTE ( pWinColor, "#", "%23" ),
                        IF (
                            [@v] < 0,
                            SUBSTITUTE ( pLossColor, "#", "%23" ),
                            SUBSTITUTE ( pTieColor, "#", "%23" )
                        )
                    )
                    & "'/>",
            "",
            [@i], ASC
        )
        RETURN
            IF (
                COUNTROWS ( _Data ) < 1,
                BLANK (),
                "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='24' viewBox='0 0 120 24'>"
                    & _Bars
                    & "</svg>"
            )

EVALUATE { VizForge.SvgWinLoss ( [Sales vs Target], 'Date'[Month Start] ) }

-- 2) Then create the measure and set Measure tools > Data category = Image URL:
-- Win Loss = VizForge.SvgWinLoss ( [Sales vs Target], '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

Feed it a signed measure such as [Sales vs Target]; place it beside the category at 24 × 120. Win/loss ticks need no shared scale, so it also works in a matrix with a single region per cell. Remember the Image URL data category. All setup steps.

Gotchas

When an SVG measure isn't enough

An interactive version can count streaks, show the actual variance in a tooltip and highlight the selected period across rows. See the SPC control chart for what an interactive version can do.

KPI card designs using it

Finished designs built on this pattern, from the KPI card gallery.