Violin Plots
Use createViolinPlot to compare kernel-density profiles inside categorical
bands. It accepts the same categorical/quantitative x/y role family as box and
gradient plots, then infers orientation from the complete field pair.
Minimal vertical violin
const program = chart()
.createCanvas()
.createData({ values })
.createViolinPlot({
x: "category",
y: "value"
});
The action creates an area mark, immutable density data, category and value scales, full closed paths, and applicable Cartesian guides. Field types are inferred when the current dataset makes one categorical and one quantitative role unambiguous.
Density width and orientation
.createViolinPlot({
x: { field: "value", fieldType: "quantitative" },
y: { field: "category", fieldType: "nominal" },
density: {
bandwidth: 0.8,
extent: [0, 30],
steps: 80,
width: { band: 0.7, resolve: "independent" }
}
})
width.band is the fraction of each categorical band available to the full
shape. resolve: "shared" uses one density maximum across categories;
"independent" gives each category its own maximum. The default is
{ band: 0.8, resolve: "shared" }.
Split a category into two halves
.createViolinPlot({
x: "category",
y: "value",
split: {
field: "period",
domain: ["early", "late"]
},
color: {
field: "period",
scale: { range: ["#4c78a8", "#e45756"] }
}
})
A split must contain exactly two observed values. The first domain value owns the left or top half and the second owns the right or bottom half. When the domain is omitted, ggaction uses first-appearance order only if exactly two values are observed.
Appearance and guides
.createViolinPlot({
x: "category",
y: "value",
color: "category",
area: { opacity: 0.7, strokeWidth: 1.5 },
guides: { legend: false }
})
When strokeWidth is supplied without a constant stroke, each outline follows
its materialized fill. A category-color legend is omitted by default because
the categorical axis already identifies the same field; request
guides: { legend: {} } to show it explicitly.
Editing
createViolinPlot is an aggregate create action. Edit the resource owned by
the decision you want to change:
const revised = program
.editDensity({
bandwidth: 1.1,
placement: {
type: "category",
width: { band: 0.6, resolve: "shared" }
}
})
.editAreaMark({ opacity: 0.55 });
Use { type: "baseline" } as the placement edit to return the area to the
ordinary zero-baseline density layout. Canvas, scale, data, filtering,
selection, highlighting, and facet changes rematerialize the complete density
paths.
Current boundary
- Exactly one categorical and one quantitative position role
- At most two split values
- Cartesian coordinates only
- No raincloud raw-point/box components, adaptive bandwidth, or Polar violin