Compound.Violin¶
Generates a Violin Plot compound SVG Visual showing distribution density using Kernel Density Estimation (KDE)
Kernel Density Estimation (KDE)
KDE creates a smooth estimate of your data's probability density by placing a "kernel" (normal distribution curve) at each data point and summing them together. The violin plot displays this density as a symmetrical shape - wider areas indicate higher probability/frequency of values.
Key Parameters:
-
Samples: Controls the resolution of the density calculation (higher = smoother, but slower performance)
-
Bandwidth: Controls how much each data point influences nearby areas. Smaller bandwidth values create sharper, more detailed curves that closely follow individual data points. Larger bandwidth values create smoother, more generalized shapes that show overall trends
DaxLib.SVG.Compound.Violin( x, y, width, height, paddingX, paddingY, axisRef, measureRef, samples, bandwidth, color )
| Parameter | Type | Required | Description |
|---|---|---|---|
| x | INT64 | The x position of the compound | |
| y | INT64 | The y position of the compound | |
| width | INT64 | The width of the compound | |
| height | INT64 | The height of the compound | |
| paddingX | DOUBLE | The horizontal padding percentage (0.0-1.0, e.g., 0.1 = 10% padding) | |
| paddingY | DOUBLE | The vertical padding percentage (0.0-1.0, e.g., 0.1 = 10% padding) | |
| axisRef | ANYREF EXPR | The column that the measure will be evaluated against | |
| measureRef | NUMERIC EXPR | The measure to evaluate | |
| samples | INT64 | Number of density calculation points | |
| bandwidth | NUMERIC | Kernel bandwidth for smoothing | |
| color | STRING | Fill color for the violin shape |
STRING An SVG violin plot showing the probability density of data using kernel density estimation
DaxLib.SVG.SVG(
500,
100,
BLANK(),
DaxLib.SVG.Compound.Violin(
0, // x
0, // y
500, // width
100, // height
0.05, // paddingX
0.02, // paddingY
Dates[Date], // axisRef
[Total Cost], // measureVal
MAX( Samples[Samples] ), // samples
MAX( Bandwidth[Bandwidth] ), // bandwidth
DaxLib.SVG.Colour.Theme(
"Power BI",
25
) // color
),
BLANK()
)
(
x: INT64,
y: INT64,
width: INT64,
height: INT64,
paddingX: DOUBLE,
paddingY: DOUBLE,
axisRef: ANYREF EXPR,
measureRef: NUMERIC EXPR,
samples: INT64,
bandwidth: NUMERIC,
color: STRING
) =>
// Apply padding to dimensions
VAR _X = x + ( width * ( COALESCE( paddingX, 0 ) / 2) )
VAR _Y = y + ( height * ( COALESCE( paddingY, 0 ) / 2))
VAR _Width = width * ( 1 - COALESCE( paddingX, 0 ) )
VAR _Height = height * ( 1 - COALESCE( paddingY, 0 ) )
// For totals
VAR _Data =
SELECTCOLUMNS(
FILTER(
VALUES( axisRef ),
NOT ISBLANK( measureRef )
),
"@Value", measureRef
)
VAR _NumValues = COUNTROWS( _Data )
VAR _InvNumValues = 1 / _NumValues
VAR _Min = MINX( _Data, [@Value] )
VAR _Max = MAXX( _Data, [@Value] )
VAR _Range = _Max - _Min
VAR _RangePerSample = _Range / samples
VAR _XWidth = _X + _Width
VAR _YHeight = _Y + _Height * 0.5
// Calculate Kernel Density Estimation using Normal distribution
VAR _KDEInput =
ADDCOLUMNS(
GENERATESERIES( 0, samples + 1, 1 ),
"@InputX", _Min + _RangePerSample * [Value]
)
VAR _KDE =
ADDCOLUMNS(
_KDEInput,
"@KDE", _InvNumValues * SUMX( _Data, NORM.DIST( [@InputX], [@Value], bandwidth, FALSE ) )
)
VAR _MaxKDE = MAXX( _KDE, [@KDE] )
// Map KDE values to SVG coordinates using normalize function
VAR _Points =
SELECTCOLUMNS(
ADDCOLUMNS(
_KDE,
"@X", DaxLib.SVG.Scale.Normalize( [@InputX], _Min, _Max, _X, _XWidth),
"@Y", DaxLib.SVG.Scale.Normalize( [@KDE], 0, _MaxKDE, _YHeight, _Y )
),
"Value", [Value],
"@X", [@X],
"@Y", [@Y]
)
// Previous point via NATURALLEFTOUTERJOIN
VAR _PointsWithPrev =
NATURALLEFTOUTERJOIN(
_Points,
SELECTCOLUMNS(
_Points,
"Value", [Value] + 1,
"@PrevX", [@X],
"@PrevY", [@Y]
)
)
// Control points + precompute segment strings once
VAR _CenterY = _Y + (_Height * 0.5)
VAR _Segs =
ADDCOLUMNS(
_PointsWithPrev,
"@CX", [@PrevX] + ( ( [@X] - [@PrevX] ) / 2 ),
"@CY", [@Y],
"@TopSeg",
IF(
[Value] = 0,
"M " & [@X] & " " & _CenterY,
"S " & ([@PrevX] + ( ( [@X] - [@PrevX] ) / 2 )) & " " & [@Y] & ", " & [@X] & " " & [@Y]
),
"@BottomSeg",
VAR _MirroredY = _CenterY + (_CenterY - [@Y])
VAR _MirroredCY = _CenterY + (_CenterY - [@Y])
RETURN
IF(
[Value] = 0,
"",
"S " & ([@PrevX] + ( ( [@X] - [@PrevX] ) / 2 )) & " " & _MirroredCY & ", " & [@X] & " " & _MirroredY
)
)
VAR _TopCurve = CONCATENATEX( _Segs, [@TopSeg], " ", [Value], ASC )
VAR _BottomCurve = CONCATENATEX( _Segs, [@BottomSeg], " ", [Value], DESC )
VAR _ViolinPath =
_TopCurve &
" " & _BottomCurve &
" Z" // Close the path
// Combined Elements
VAR _CombinedElements =
DaxLib.SVG.Element.Paths(
_ViolinPath, // d
DaxLib.SVG.Attr.Shapes(
color, // fill
0.5, // fillOpacity
BLANK(), // fillRule
color, // stroke
1, // strokeWidth
BLANK(), // strokeOpacity
BLANK() // opacity
),
BLANK() // transforms
)
RETURN
IF( NOT ISEMPTY( _Data ), _CombinedElements )