Violin Plot (Julia)

Author

[Editor] Bizard Team.

Modified

2026-04-04

🤖 AI Skill — Copy this tutorial's skill into your AI assistant

A violin plot combines box plot statistics with kernel density estimation to show data distributions. Julia’s CairoMakie makes it straightforward to create violin plots for comparing gene expression, biomarker levels, or clinical measurements across groups.

Example

Setup

  • System Requirements: Cross-platform (Linux/MacOS/Windows)
  • Programming Language: Julia
  • Dependencies: CairoMakie, DataFrames, Statistics
using CairoMakie
using DataFrames
using Statistics
using Random

Data Preparation

Random.seed!(42)
n_per = 80
groups = vcat(fill("Tumor", n_per), fill("Normal", n_per), fill("Adjacent", n_per))
expression = vcat(
    randn(n_per) .* 1.5 .+ 8,
    randn(n_per) .* 1.2 .+ 5,
    randn(n_per) .* 1.8 .+ 6.5
)
group_idx = vcat(fill(1, n_per), fill(2, n_per), fill(3, n_per))
df = DataFrame(Group=groups, Expression=expression, GroupIdx=group_idx)
240×3 DataFrame
215 rows omitted
Row Group Expression GroupIdx
String Float64 Int64
1 Tumor 7.45496 1
2 Tumor 8.37761 1
3 Tumor 7.52752 1
4 Tumor 7.53312 1
5 Tumor 9.22446 1
6 Tumor 8.71511 1
7 Tumor 6.71067 1
8 Tumor 5.79607 1
9 Tumor 4.8285 1
10 Tumor 8.06567 1
11 Tumor 6.762 1
12 Tumor 9.26043 1
13 Tumor 8.65083 1
229 Adjacent 8.67822 3
230 Adjacent 5.35136 3
231 Adjacent 6.22416 3
232 Adjacent 3.53355 3
233 Adjacent 8.33217 3
234 Adjacent 6.73736 3
235 Adjacent 11.0713 3
236 Adjacent 6.77344 3
237 Adjacent 7.34419 3
238 Adjacent 5.31451 3
239 Adjacent 5.72756 3
240 Adjacent 3.46341 3

Visualization

Basic Violin Plot

fig = Figure(size=(700, 500))
ax = Axis(fig[1,1], xlabel="Group", ylabel="Expression Level",
          title="Gene Expression Distribution",
          xticks=(1:3, ["Tumor", "Normal", "Adjacent"]))
violin!(ax, df.GroupIdx, df.Expression, color=(:steelblue, 0.7))
fig
Figure 1: Basic Violin Plot of Gene Expression

Grouped Violin with Box Plot Overlay

fig2 = Figure(size=(700, 500))
ax2 = Axis(fig2[1,1], xlabel="Group", ylabel="Expression Level",
           title="Violin + Box Plot",
           xticks=(1:3, ["Tumor", "Normal", "Adjacent"]))
colors = [:red, :steelblue, :green]
for (i, g) in enumerate(["Tumor", "Normal", "Adjacent"])
    mask = df.Group .== g
    vals = df.Expression[mask]
    violin!(ax2, fill(i, sum(mask)), vals, color=(colors[i], 0.4), side=:left)
    boxplot!(ax2, fill(i, sum(mask)), vals, color=(colors[i], 0.7), width=0.3)
end
fig2
Figure 2: Violin Plot with Box Plot Overlay

Half Violin (Raincloud) Plot

fig3 = Figure(size=(800, 500))
ax3 = Axis(fig3[1,1], xlabel="Group", ylabel="Expression Level",
           title="Raincloud Plot",
           xticks=(1:3, ["Tumor", "Normal", "Adjacent"]))
for (i, g) in enumerate(["Tumor", "Normal", "Adjacent"])
    mask = df.Group .== g
    vals = df.Expression[mask]
    violin!(ax3, fill(i, sum(mask)), vals, color=(colors[i], 0.5), side=:right)
    scatter!(ax3, fill(i, sum(mask)) .- 0.15 .+ randn(sum(mask)) .* 0.03,
             vals, color=(colors[i], 0.3), markersize=5)
end
fig3
Figure 3: Raincloud-style Half Violin Plot

References

  1. Danisch, S., & Krumbiegel, J. (2021). Makie.jl: Flexible high-performance data visualization for Julia. JOSS, 6(65), 3349.