- Charts
- Line Chart
- Bar Chart
- Area Chart
- Scatter Chart
- Pie Chart
- Donut Chart
- Dot Plot Chart
- Lollipop Chart
- Dumbbell Chart
- Slope Chart
- Range Chart
- Histogram Chart
- Box Plot Chart
- Violin Chart
- Polar Chart
- Parallel Coordinates
- SPLOM Chart
- Parcats Chart
- Candlestick Chart
- OHLC Chart
- Waterfall Chart
- Funnel Chart
- Heatmap Chart
- Contour Chart
- Density Chart
- Ternary Chart
- Radar Chart
- Treemap Chart
- Sunburst Chart
- Sankey Chart
- Gauge Chart
- Bullet Chart
- Icicle Chart
- Network Graph
- Dendrogram
- Choropleth Chart
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data with normal-ish distribution
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
const data = [
{ category: "Engineering", values: generateData(78, 12, 80, 1) },
{ category: "Sales", values: generateData(72, 15, 80, 2) },
{ category: "Marketing", values: generateData(75, 10, 80, 3) },
{ category: "Support", values: generateData(70, 18, 80, 4) },
]
export function ViolinChartDemo() {
return <ViolinChart data={data} showBoxPlot showMedian />
}
About
Violin Charts combine box plots with kernel density estimation (KDE) to show the full distribution shape of data. The width of the violin at each value represents the probability density. Perfect for comparing distributions across multiple categories.
Installation
pnpm dlx shadcn@latest add https://ui.simplifying.ai/r/violin-chart.json
Usage
import { ViolinChart } from "@/components/ui/charts"
const data = [
{ category: "Group A", values: [12, 15, 18, 22, 25, 28, 30, 32, 35] },
{ category: "Group B", values: [8, 12, 15, 20, 25, 30, 35, 40, 45] },
]
export function Example() {
return <ViolinChart data={data} showBoxPlot showMedian />
}Examples
Default (Standard)
Standard violin chart with box plot overlay and median markers.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data with normal-ish distribution
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
const data = [
{ category: "Engineering", values: generateData(78, 12, 80, 1) },
{ category: "Sales", values: generateData(72, 15, 80, 2) },
{ category: "Marketing", values: generateData(75, 10, 80, 3) },
{ category: "Support", values: generateData(70, 18, 80, 4) },
]
export function ViolinChartDemo() {
return <ViolinChart data={data} showBoxPlot showMedian />
}
Comparison
Before and after treatment comparison.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
// Simple before/after comparison
const data = [
{ category: "Before", values: generateData(45, 15, 100, 10) },
{ category: "After", values: generateData(68, 12, 100, 20) },
]
export function ViolinChartComparisonDemo() {
return <ViolinChart data={data} showBoxPlot showMedian color="#22c55e" />
}
Box Plot Only
Shows only the box plot without the violin shape.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
// Box plot only variant - no violin shape
const data = [
{ category: "Q1", values: generateData(82, 8, 50, 1) },
{ category: "Q2", values: generateData(78, 12, 50, 2) },
{ category: "Q3", values: generateData(85, 10, 50, 3) },
{ category: "Q4", values: generateData(90, 6, 50, 4) },
]
export function ViolinChartBoxplotDemo() {
return (
<ViolinChart data={data} variant="boxplot" showMedian color="#8b5cf6" />
)
}
Grouped
Test scores across multiple subjects.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
// Test scores across multiple subjects
const data = [
{ category: "Math", values: generateData(72, 14, 80, 1) },
{ category: "Science", values: generateData(68, 16, 80, 2) },
{ category: "English", values: generateData(75, 12, 80, 3) },
{ category: "History", values: generateData(70, 15, 80, 4) },
{ category: "Art", values: generateData(80, 10, 80, 5) },
]
export function ViolinChartGroupedDemo() {
return <ViolinChart data={data} showBoxPlot showMedian />
}
Custom Color
API response times with custom color.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
// API response time distribution
const data = [
{ category: "GET /users", values: generateData(45, 20, 100, 1) },
{ category: "POST /orders", values: generateData(120, 40, 100, 2) },
{ category: "GET /products", values: generateData(35, 15, 100, 3) },
{ category: "PUT /cart", values: generateData(85, 25, 100, 4) },
]
export function ViolinChartHorizontalDemo() {
return (
<ViolinChart
data={data}
showBoxPlot
showMedian
color="#06b6d4"
valueFormatter={(v) => `${v.toFixed(0)}ms`}
/>
)
}
Minimal
Simple distribution without box plot overlay.
"use client"
import { ViolinChart } from "@/components/ui/charts"
// Generate sample data
const generateData = (mean: number, std: number, n: number, seed: number) => {
const values: number[] = []
let s = seed
for (let i = 0; i < n; i++) {
s = (s * 9301 + 49297) % 233280
const u1 = s / 233280
s = (s * 9301 + 49297) % 233280
const u2 = s / 233280
const z = Math.sqrt(-2 * Math.log(u1 || 0.001)) * Math.cos(2 * Math.PI * u2)
values.push(mean + std * z)
}
return values
}
// Simple age distribution - minimal style without box plot
const data = [
{ category: "Group A", values: generateData(35, 10, 60, 1) },
{ category: "Group B", values: generateData(42, 12, 60, 2) },
{ category: "Group C", values: generateData(38, 8, 60, 3) },
]
export function ViolinChartMinimalDemo() {
return <ViolinChart data={data} showBoxPlot={false} showMedian />
}
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| data | ViolinDataPoint[] | required | Violin data |
| variant | "standard" | "boxplot" | "minimal" | "standard" | Visual style |
| showBoxPlot | boolean | true | Show box plot overlay |
| showMedian | boolean | true | Show median marker |
| showGrid | boolean | true | Show grid lines |
| bandwidth | number | auto | KDE bandwidth (auto-calculated) |
| resolution | number | 50 | KDE resolution (smoothness) |
| color | string | "#3b82f6" | Color for all violins |
| valueFormatter | function | toFixed(0) | Format display values |
Data Format
interface ViolinDataPoint {
category: string // Category label
values: number[] // Array of numeric values
}Variants
Standard
Full mirrored violin with optional box plot and median. Best for showing complete distribution shapes.
Box Plot
Shows only the box plot without the violin density shape. Classic statistical visualization.
Minimal
Simplified view focusing on the violin shape without overlays.
Features
- Kernel Density Estimation: Automatic bandwidth calculation using Silverman's rule
- Box plot overlay: Shows quartiles (Q1, median, Q3) and whiskers (min/max)
- Interactive tooltips: Hover to see detailed statistics
- Single consistent color: Clean, professional appearance
- Dark mode support: Proper styling for both themes