SVG generation via DAX measures and extension measures with ImageUrl data category for inline visualizations in PBIR reports. Automatically invoke when the user mentions "SVG visual", "DAX sparkline", "SVG measure", "inline graphics with DAX", "ImageUrl data category", "extension measure", or asks to create any DAX-generated chart (progress bars, bullet charts, KPI indicators, data bars, gauges, donut charts, lollipop charts, dumbbell charts, status pills, overlapping bars, boxplots, IBCS bars, jitter plots, box-and-whisker charts).
Report modification requires tooling. Two paths exist:
pbirCLI (preferred) -- use thepbircommand and thepbir-cliskill. Install withuv tool install pbir-cliorpip install pbir-cli. Check availability withpbir --version.- Direct JSON modification -- if
pbiris not available, use thepbir-formatskill (pbip plugin) for PBIR JSON structure and patterns. Validate every change withjq empty <file.json>.If neither the
pbir-cliskill nor thepbir-formatskill is loaded, ask the user to install the appropriate plugin before proceeding with report modifications.
Generate inline SVG graphics using DAX measures that return SVG markup strings. These render as images in table, matrix, card, image, and slicer visuals. Store as extension measures in reportExtensions.json.
data:image/svg+xml;utf8,dataCategory is set to ImageUrl| Visual | visualType | Binding | Reference |
|---|---|---|---|
| Table | tableEx | grid.imageHeight / grid.imageWidth | references/svg-table-matrix.md |
| Matrix | pivotTable | Same as table | references/svg-table-matrix.md |
| Image | image | sourceType='imageData' + sourceField | references/svg-image-visual.md |
| Card (New) | cardVisual | callout.imageFX | references/svg-card-slicer.md |
| Slicer (New) | advancedSlicerVisual | Header images | references/svg-card-slicer.md |
Before writing DAX, design the SVG visually:
/tmp/mockup.svg and open it in a browser to preview layout, colors, and proportions.# -- e.g., fill='#2B7A78'. Never use %23 URL encoding or named colors. Always hex.Create the extension measure in reportExtensions.json manually (see the pbir-format skill in the pbip plugin for JSON structure).
# Example using pbir_object_model (if available):
report.add_extension_measure(
table="Orders",
name="Sparkline SVG",
expression='''
VAR _Prefix = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 30'>"
VAR _Bar = "<rect x='0' y='0' width='50' height='30' fill='#2196F3'/>"
VAR _Suffix = "</svg>"
RETURN _Prefix & _Bar & _Suffix
''',
data_type="Text",
data_category="ImageUrl",
display_folder="SVG Charts",
)
report.save()
Before presenting the measure to the user, dispatch the svg-reviewer agent to validate syntax and provide design feedback.
Extension measures use "Schema": "extension" in the SourceRef:
{
"field": {
"Measure": {
"Expression": {
"SourceRef": {"Schema": "extension", "Entity": "Orders"}
},
"Property": "Sparkline SVG"
}
}
}
For image visuals, set sourceType='imageData' with sourceField in the visual.json (see references/svg-image-visual.md).
Validate JSON syntax with jq empty <reportExtensions.json> and inspect the file to confirm measure definitions and data categories.
Before writing a custom SVG measure from scratch, check whether an existing UDF library already provides the chart type:
To check if a library is installed, look for functions/measures starting with PowerofBI.IBCS., Viz., Compound., or Element.. Only write custom SVG DAX when no library function covers the required visualization. See references/community-examples.md for full function listings and additional libraries.
UDF libraries are installed into the semantic model, not the report. Use one of these tools:
te command) -- use the te-docs skill for guidanceconnect-pbid skill -- connect to Power BI Desktop's local Analysis Services instance via TOM/PowerShelltmdl skill -- edit TMDL files directly in a PBIP project (last resort)Every SVG measure must follow a strict VAR-based structure. Organize code into clearly separated regions:
SVG Measure =
-- CONFIG: Input fields and visual parameters
VAR _Actual = [Sales Amount]
VAR _Target = [Sales Target]
VAR _Scope = ALLSELECTED ( 'Product'[Category] )
-- CONFIG: Colors
VAR _BarColor = "#5B8DBE"
VAR _TargetColor = "#333333"
-- NORMALIZATION: Scale values to SVG coordinate space
VAR _AxisMax = CALCULATE( MAXX( _Scope, [Sales Amount] ), REMOVEFILTERS( 'Product'[Category] ) ) * 1.1
VAR _AxisRange = 100
VAR _ActualNormalized = DIVIDE( _Actual, _AxisMax ) * _AxisRange
-- SVG ELEMENTS: One VAR per visual element
VAR _SvgPrefix = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 25'>"
VAR _Sort = "<desc>" & FORMAT( _Actual, "000000000000" ) & "</desc>"
VAR _Bar = "<rect x='0' y='5' width='" & _ActualNormalized & "' height='15' fill='" & _BarColor & "'/>"
VAR _TargetLine = "<rect x='" & DIVIDE( _Target, _AxisMax ) * _AxisRange & "' y='2' width='2' height='21' fill='" & _TargetColor & "'/>"
VAR _SvgSuffix = "</svg>"
-- ASSEMBLY: Combine in rendering order (back to front)
VAR _SVG = _SvgPrefix & _Sort & _Bar & _TargetLine & _SvgSuffix
RETURN _SVG
Key conventions:
<rect>, <circle>, <text>, <line>, etc.<desc> sort trick -- embed FORMAT(_Actual, "000000000000") in a <desc> tag so the table/matrix can sort by the SVG columnSVG coordinates must be normalized to a fixed range. Raw measure values (e.g., 1,234,567) cannot be used directly as pixel coordinates. The standard pattern:
-- 1. Define the SVG coordinate range
VAR _BarMin = 0 -- leftmost position (or offset for labels)
VAR _BarMax = 100 -- rightmost position
-- 2. Find the maximum value across all rows in the visual's filter context
VAR _Scope = ALLSELECTED( 'Table'[GroupColumn] )
VAR _MaxInScope = CALCULATE( MAXX( _Scope, [Measure] ), REMOVEFILTERS( 'Table'[GroupColumn] ) )
VAR _AxisMax = _MaxInScope * 1.1 -- 10% padding
-- 3. Normalize each value to the SVG range
VAR _AxisRange = _BarMax - _BarMin
VAR _Normalized = DIVIDE( _Actual, _AxisMax ) * _AxisRange
Use ALLSELECTED for the scope when the chart should respond to slicer context. Use ALL for a fixed axis across all filter contexts. The * 1.1 padding prevents bars from touching the edge.
Table/matrix SVG measures must guard against subtotal/total rows where multiple categories are in scope:
IF( HASONEVALUE( 'Table'[GroupColumn] ),
-- SVG code here
)
Without this guard, the measure evaluates on grand total rows with meaningless aggregated values.
fill='#2196F3'"" (DAX convention)viewBox for responsive scaling: viewBox='0 0 100 25'xmlns required on <svg> element# only -- e.g., fill='#2196F3'. %23 URL encoding causes errors in image visuals. Never use named colors._Height - _ValueviewBox with a 0-100 range for normalized coordinatesFor sparklines and multi-point charts, build coordinate strings with CONCATENATEX:
VAR _Points = CONCATENATEX(
_SparklineTable,
[X] & "," & (100 - [Y]),
" ",
[Date], ASC
)
-- Produces: "0,80 10,60 20,40 30,20"
-- Use in: <polyline points='...'/>
<desc> sort trick -- embed formatted value in <desc> for sortable SVG columnsviewBox for responsive scaling instead of fixed width/heightdisplay_folder to organize SVG measures together (e.g., "SVG Charts")/tmp/, open in browser, iterate before writing DAX# directly, never %23 URL encodingquery block -- only objects.image with sourceType='imageData' and sourceField{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/reportExtension/1.0.0/schema.json",
"name": "extension",
"entities": [{
"name": "ExistingTable",
"measures": [{
"name": "Sparkline SVG",
"dataType": "Text",
"dataCategory": "ImageUrl",
"expression": "...",
"displayFolder": "SVG Charts"
}]
}]
}
cardVisual insteadSVG measures are the preferred choice for simple inline graphics embedded in tables, matrices, cards, and image visuals. Use SVG when you need:
Use Deneb instead for complex, interactive visualizations (cross-filtering, tooltips, hover states) or chart types that require extensive data transforms. Use Python/R instead for statistical analysis charts (distributions, regressions, correlations).
references/community-examples.md -- Community SVG templates organized by target visual type (Table/Matrix, Image, Card), including DaxLib.SVG functions, Kerry Kolosko templates, and PowerBI MacGuyver Toolbox patternsreferences/svg-table-matrix.md -- Patterns for Table/Matrix: data bar, bullet chart, dumbbell, overlapping bars, lollipop, status pill, sparkline, bar sparkline, area sparkline, UDF patterns. Includes axis normalization, sort trick, and image size configuration.references/svg-image-visual.md -- Patterns for Image visuals: KPI header, sparkline with endpoint, dashboard tile. Covers sourceType, Python API, and design considerations.references/svg-card-slicer.md -- Patterns for Card/Slicer: arrow indicator, mini gauge, mini donut, progress bar. Card binding via callout.imageFX.references/svg-elements.md -- SVG element reference (rect, circle, line, polyline, text, path, gradient, group)Ready-to-use DAX measure expressions in examples/:
sparkline-measure.dax -- Line sparkline (polyline + CONCATENATEX)progress-bar-measure.dax -- Conditional progress bardumbbell-chart-measure.dax -- Actual vs target dumbbellbullet-chart-measure.dax -- Bullet chart with sentiment action dotsoverlapping-bars-measure.dax -- Overlapping bars with variance labelboxplot-measure.dax -- Box-and-whisker plot (inspired by DaxLib.SVG)ibcs-bar-measure.dax -- IBCS-compliant horizontal bar (inspired by avatorl)jitter-plot-measure.dax -- Dot strip chart with jitter (inspired by DaxLib.SVG)overlapping-bars-with-variance-measure.dax -- Overlapping bars with variance bar + arrow icon + % label (Kurt Buhler / Data Goblins)lollipop-conditional-measure.dax -- Lollipop with scaled dot + auto-formatted label (Kurt Buhler / Data Goblins)waterfall-measure.dax -- Waterfall with cumulative OFFSET positioning + connector lines (Kurt Buhler / Data Goblins)status-pill-measure.dax -- Rounded pill badge with category color + text label (Kurt Buhler / Data Goblins)| Library | Author | Key Features |
|---|---|---|
| DaxLib.SVG | Jake Duddy | UDF library: area, line, boxplot, heatmap, jitter, violin |
| PBI-Core-Visuals-SVG-HTML | David Bacci | Chips, tornado, gradient matrix, bar UDF |
| PowerBI MacGuyver Toolbox | Stepan Resl / Data Goblins | 20+ bar, 14+ line, 24+ KPI templates |
| Dashboard Design UDF Library | Dashboard-Design | Target line bars, pill visuals |
| Kerry Kolosko Templates | Kerry Kolosko | Sparklines, data bars, KPI cards |
pbi-report-design -- Layout and design best practicesdeneb-visuals -- Vega/Vega-Lite for complex interactive visualizationspython-visuals -- matplotlib/seaborn for statistical chartsr-visuals -- ggplot2 for statistical chartspbir-format (pbip plugin) -- PBIR JSON format reference (extension measures, ImageUrl binding)