Violin and half (split) violin plots in Python with canvasxpress

Python
canvasxpress
violin
visualization
Show a full distribution per group as a violin, then split it in half to compare two conditions side by side — interactive and reproducible, in Python.
Author

Isaac Neuhaus

Published

September 26, 2026

A violin plot shows the full shape of a distribution instead of collapsing it to a box’s quartiles. And when you want to compare two conditions at the same position, a split (half) violin puts one condition on each half. Here we build both in Python with canvasxpress — interactive and reproducible.

Install

pip install canvasxpress

The data

A measurement across a few dose groups and two conditions. Swap in your own long-format table.

import numpy as np

rng = np.random.default_rng(1)
doses = ["Low", "Medium", "High"]
conds = ["Control", "Treated"]

value, Dose, Condition = [], [], []
for d in doses:
    for co in conds:
        mu = {"Low": 6, "Medium": 8, "High": 10}[d] + (1.5 if co == "Treated" else 0)
        value += list(np.round(rng.normal(mu, 1.2, 40), 2))
        Dose += [d] * 40
        Condition += [co] * 40

In canvasXpress terms a violin is a Boxplot graph with the violin turned on: one measured variable × N observations, with the grouping columns as sample annotations (x).

from canvasxpress.canvas import CanvasXpress
from canvasxpress.render.jupyter import CXNoteBook
from IPython.display import display

ids = [f"o{i+1}" for i in range(len(value))]
data = {"y": {"vars": ["value"], "smps": ids, "data": [value]},
        "x": {"Dose": Dose, "Condition": Condition}}

A full violin per group

cx = CanvasXpress(render_to="violin", data=data, config={
    "graphType": "Boxplot", "showViolinBoxplot": True, "violinScale": "area",
    "groupingFactors": ["Dose"], "xAxis": ["value"], "smpTitle": "Dose",
    "title": "Distribution of value by dose",
}, width=650, height=500)
for part in CXNoteBook(cx).render():
    display(part)

A split (half) violin comparing two conditions

Group by both factors, colour by condition, and set violinSide = "split" — the two conditions share each dose position, one on each half.

cx = CanvasXpress(render_to="violinSplit", data=data, config={
    "graphType": "Boxplot", "showViolinBoxplot": True, "violinScale": "area",
    "groupingFactors": ["Dose", "Condition"], "colorBy": "Condition",
    "violinSide": "split", "violinTrim": False, "xAxis": ["value"], "smpTitle": "Dose",
    "title": "Control vs Treated — split violin by dose",
}, width=650, height=500)
for part in CXNoteBook(cx).render():
    display(part)

Hover to read the density and summary stats. violinSide can also be "lt" or "rb" for a one-sided half violin.

Why “reproducible”

The data+config is the figure — one portable JSON spec that renders the identical violins from R or JavaScript.

Next