バイオリンプロットライブラリ比較
2つのライブラリで同じデータを表示し、実装方法とスタイルを比較
このページでは、Plotly.js・D3.jsを使ったバイオリンプロット(Violin Plot)の実装パターンをインタラクティブなデモとコードで確認できます。
1. Plotly.js (react-plotly.js)
type: 'violin' でネイティブサポート。ボックスプロットや平均線を重ねて表示でき、ホバー時に詳細な統計情報を確認できる。
✓ ネイティブ violin 型✓ ズーム・ホバー標準装備✓ box / points 重ねて表示
チャートを読み込み中...
特徴:
type: 'violin' を指定するだけでKDE計算から描画まで自動処理される。box.visible: true でボックスプロットを重ね表示でき、ほとんどのユースケースで最初の選択肢になる。tsx
'use client';
import dynamic from 'next/dynamic';
const Plot = dynamic(() => import('react-plotly.js'), { ssr: false });
const dataMap: Record<string, number[]> = {
'グループA': [52,58,61,63,65,67,68,69,70,71,72,73,74,75,76,77,78,80,83,88],
'グループB': [40,45,50,55,58,60,62,65,68,70,72,75,78,80,83,85,88,90,93,98],
'グループC': [60,62,64,65,66,67,68,69,70,71,71,72,72,73,74,75,76,77,78,80],
};
const colors = ['#4f86c6', '#f59e0b', '#10b981'];
export function PlotlyViolin() {
const traces = Object.entries(dataMap).map(([name, y], i) => ({
type: 'violin' as const,
name,
y,
box: { visible: true },
meanline: { visible: true },
points: 'none' as const,
fillcolor: colors[i],
line: { color: colors[i] },
opacity: 0.7,
}));
return (
<Plot
data={traces}
layout={{
yaxis: { title: '値' },
violingap: 0.3,
violinmode: 'group',
margin: { t: 20, b: 40, l: 50, r: 20 },
height: 400,
showlegend: true,
paper_bgcolor: 'transparent',
plot_bgcolor: 'transparent',
}}
config={{ displayModeBar: false }}
style={{ width: '100%' }}
/>
);
}🤖 AIプロンプトテンプレート
React + Tailwind CSSで、Plotly.jsを使ったバイオリンプロットを実装してください。 - 使用ライブラリ: react-plotly.js(next/dynamicでSSR無効化) - type: 'violin' を使用 - 3グループのデータを並べて表示(violinmode: 'group') - box.visible: true でボックスプロットを重ねて表示 - meanline.visible: true で平均線を表示 - ホバー時に統計情報(中央値・四分位など)を表示 - サンプルデータ: グループA・B・C 各20サンプル
⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。
2. D3.js カスタム実装(KDE)
エパネチニコフカーネルによるKDE(カーネル密度推定)を自前で実装してSVGでバイオリン形状を描画。形状・色・アニメーションを完全にコントロールできる。
✓ 完全カスタマイズ可能✓ KDE アルゴリズムを学べる✓ 外部依存ゼロで軽量
特徴: エパネチニコフカーネルでKDEを計算し、各閾値点における密度をSVGパスとして描画する。 学習コストは高いが、形状・色・アニメーションを完全にコントロールできる。デザインにこだわりたい場合や独自の可視化が必要な場合に有効。
tsx
'use client';
import { useRef, useEffect } from 'react';
import * as d3 from 'd3';
const dataMap: Record<string, number[]> = {
'グループA': [52,58,61,63,65,67,68,69,70,71,72,73,74,75,76,77,78,80,83,88],
'グループB': [40,45,50,55,58,60,62,65,68,70,72,75,78,80,83,85,88,90,93,98],
'グループC': [60,62,64,65,66,67,68,69,70,71,71,72,72,73,74,75,76,77,78,80],
};
const colors = ['#4f86c6', '#f59e0b', '#10b981'];
// エパネチニコフカーネル
function kernelEpanechnikov(bandwidth: number) {
return (x: number) =>
Math.abs(x /= bandwidth) <= 1 ? (0.75 * (1 - x * x)) / bandwidth : 0;
}
// カーネル密度推定(KDE)を自前で実装している
function kde(
kernel: (x: number) => number,
thresholds: number[],
data: number[],
) {
return thresholds.map(
x => [x, d3.mean(data, d => kernel(x - d))] as [number, number],
);
}
export function D3Violin() {
const ref = useRef<SVGSVGElement>(null);
useEffect(() => {
if (!ref.current) return;
const svg = d3.select(ref.current);
svg.selectAll('*').remove();
const margin = { top: 20, right: 30, bottom: 40, left: 50 };
const width = ref.current.clientWidth - margin.left - margin.right;
const height = 360 - margin.top - margin.bottom;
const g = svg
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
const groups = Object.keys(dataMap);
const allValues = Object.values(dataMap).flat();
const xScale = d3.scaleBand().domain(groups).range([0, width]).padding(0.3);
const yScale = d3.scaleLinear()
.domain([d3.min(allValues)! - 5, d3.max(allValues)! + 5])
.range([height, 0]);
g.append('g').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale));
g.append('g').call(d3.axisLeft(yScale));
const bandwidth = 5;
const kernel = kernelEpanechnikov(bandwidth);
const thresholds = d3.range(
d3.min(allValues)! - 10,
d3.max(allValues)! + 10,
1,
);
groups.forEach((group, i) => {
const data = dataMap[group];
const density = kde(kernel, thresholds, data);
const maxDensity = d3.max(density, d => d[1])!;
const halfWidth = (xScale.bandwidth() / 2) * 0.9;
const xViolin = d3.scaleLinear()
.domain([-maxDensity, maxDensity])
.range([-halfWidth, halfWidth]);
const area = d3.area<[number, number]>()
.x0(d => xViolin(-d[1]))
.x1(d => xViolin(d[1]))
.y(d => yScale(d[0]))
.curve(d3.curveCatmullRom);
const cx = xScale(group)! + xScale.bandwidth() / 2;
g.append('path')
.datum(density)
.attr('transform', `translate(${cx},0)`)
.attr('d', area)
.attr('fill', colors[i])
.attr('opacity', 0.7)
.attr('stroke', colors[i])
.attr('stroke-width', 1);
});
}, []);
return <svg ref={ref} style={{ width: '100%', height: 400 }} />;
}🤖 AIプロンプトテンプレート
React + Tailwind CSSで、D3.jsを使ったバイオリンプロットを実装してください。 - 使用ライブラリ: d3 - useRef + useEffect でSVGを直接操作 - エパネチニコフカーネルによるKDE(カーネル密度推定)を実装 - d3.area() で左右対称のバイオリン形状を描画 - xScaleはd3.scaleBand、yScaleはd3.scaleLinear - 3グループを横並びで表示 - サンプルデータ: グループA・B・C 各20サンプル
⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。
ライブラリ比較
| ライブラリ | バイオリン対応 | 実装難易度 | インタラクション | おすすめ用途 |
|---|---|---|---|---|
| Plotly.js | ネイティブ(violin) | 低 | ズーム・ホバー・box/points表示 | データ分析・科学系・素早い実装 |
| D3.js | カスタム実装(KDE) | 高 | 自由に実装可能 | 高度なカスタマイズ・学習目的 |
選択のポイント
- •Plotly.js:
type: 'violin'でそのまま動く。box.visible・pointsオプションでボックスプロットや散布点を重ねられるなど表現力が高く、ほとんどのユースケースで最初の選択肢になる。 - •D3.js: カーネル密度推定(KDE)を自前で実装するため学習コストは高いが、形状・色・アニメーションを完全にコントロールできる。デザインにこだわりたい場合や独自の可視化が必要な場合に有効。
バイオリンプロットは、データの分布形状(密度)を視覚化するグラフ。ボックスプロットより詳細な分布の形状(密度)を確認できる。
グループ間の分布比較・外れ値の検出・データの偏り確認など、統計分析や科学系データの可視化に適している。
主なバリエーション
- •ボックスプロット重ね(box.visible)
- •平均線表示(meanline)
- •散布点重ね(points: 'all')
- •横向きバイオリン(orientation: 'h')
- •グループ比較(violinmode: 'group')
📊 使用しているサンプルデータ(クリックで表示)
3グループ各20サンプルの数値データを使用しています。グループAは中央集中型、グループBは広い分布、グループCは高い中央値で分布が狭い特徴を持ちます。