Violin Plots in Python
A violin plot (also called a violin chart or violin graph) shows the full
estimated density of a distribution as a mirrored curve, revealing multi-modal
shapes that a box plot hides. With xy
you build a violin plot in Python that compares several groups side by side and
stays interactive — pan, zoom, and hover across every curve.
Jump to creating a violin plot, density resolution, or options.
Create a Violin Plot
Pass a list of arrays — one per group — to violin, and label each group with
x. This is the minimal Python violin plot:
Density Resolution and Orientation
The bins option sets the resolution of the estimated density: more bins trace
a finer curve, fewer bins smooth it out. Switch orientation to
"horizontal" when group labels are long, and use width to control how wide
each violin sits within its slot. The example above overlays a single-peak
group against a two-peak group so the multi-modal shape is obvious.
Horizontal Violins at High Resolution
Raise bins for a finer density trace, turn the plot sideways with
orientation="horizontal", and tune the fill with width and opacity.
Violin and Box Overlay
Compose violin and a narrow box on the same groups inside a neutral
xy.chart(...) so each distribution shows its full density and its quartiles.
Violin Plot Options
Pass column names with data= instead of arrays when your data is a table.
Related Charts
- Box plots — summarize a distribution with quartiles instead of a full curve.
- Histograms — bin one distribution into bars.
API Reference
xy.violin_chart
A violin chart composing `violin` marks.
Props
| Prop | Type | Description |
|---|---|---|
*children | Component | Marks, axes, annotations, and chart chrome. |
title | Optional[str] | Title shown above the plot. |
width | int | str | Chart width in pixels or a CSS size such as ``"100%"``. |
height | int | str | Chart height in pixels or a CSS size such as ``"100%"``. |
padding | Union[float, Sequence[float], None] | Plot margins, as one value or a sequence of side values. Use zero for an edge-to-edge sparkline. |
data | TableLike | Chart-level data used by marks that omit their own ``data``. |
class_name | Optional[str] | CSS class applied to the chart container. |
class_names | Optional[dict[str, str]] | CSS classes keyed by stable chart DOM slot. |
style | Optional[dict[str, StyleValue]] | Inline style overrides for the chart container. |
styles | Optional[dict[str, dict[str, StyleValue]]] | Inline style mappings keyed by stable chart DOM slot. |
on_hover | Optional[Callable[[dict], None]] | Callback receiving hover event payloads. |
on_click | Optional[Callable[[dict], None]] | Callback receiving picked-mark click payloads. |
on_brush | Optional[Callable[[dict], None]] | Callback receiving brush event payloads. |
on_select | Optional[Callable[[Selection], None]] | Callback receiving data-space selections. |
on_view_change | Optional[Callable[[dict], None]] | Callback receiving viewport change payloads. |
hover | Optional[bool] | Whether pointer movement emits hover events. |
click | Optional[bool] | Whether picked marks emit click events. |
select | Optional[bool] | Whether shift-drag box selection is enabled. |
brush | Optional[bool] | Whether brush selection is enabled. |
crosshair | Optional[bool] | Whether plot-aligned hover guides are shown. |
navigation | Optional[bool] | Whether browser pan and zoom navigation is enabled. |
pan | Optional[bool] | Whether plain-drag panning is enabled. |
pan_axes | Optional[tuple[str, ...]] | Declared axis IDs translated by pan gestures. |
zoom | Optional[bool] | Whether viewport zoom is enabled. |
default_drag_action | Optional[DefaultDragAction] | Initial action performed by a plain plot drag. |
zoom_axes | Optional[tuple[str, ...]] | Declared axis IDs changed by zoom gestures and controls. |
zoom_limits | Optional[ZoomLimits] | Minimum and maximum magnification globally or by axis. |
wheel_zoom | Optional[bool] | Whether wheel and trackpad zoom is available. |
box_zoom | Optional[bool] | Whether box zoom is available as a drag action. |
zoom_buttons | Optional[bool] | Whether modebar Zoom In/Out commands are available. |
double_click_reset | Optional[bool] | Whether double-click restores ``reset_axes``. |
reset_axes | Optional[tuple[str, ...]] | Declared axis IDs restored by reset. |
link_group | Optional[str] | Identifier used to synchronize charts in the browser. |
link_axes | Optional[tuple[str, ...]] | Axes synchronized within the link group. |
FAQ
How do I make a violin plot in Python?
Pass a list of arrays to xy.violin(...), one per group, inside
xy.violin_chart(...) and render it. The density curves and axes are computed
automatically.
What does the width of a violin plot mean?
The width at any level reflects the estimated density of values there — wider
regions have more data. Use the width option to scale the whole violin within
its slot.
How do I control the smoothness of a violin plot?
Set bins on violin. More bins trace a finer, more detailed density curve;
fewer bins produce a smoother, simpler shape.
When should I use a violin plot instead of a box plot?
Use a violin plot when the shape matters — especially to reveal multi-modal distributions. A box plot only shows quartiles, so it hides multiple peaks.