はじめに
D3は、あらゆるJavaScript環境で動作します。
オンラインでD3を試す
D3を始める(そして助けを得る)ための最も速い方法は、Observableを利用することです!D3は、Observableの標準ライブラリの一部として、ノートブックでデフォルトで使用できます。D3で何かを作成するには、生成されたDOM要素をセルから返します。以下は、開始するための空白のグラフです。
{
// Declare the chart dimensions and margins.
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
.domain([new Date("2023-01-01"), new Date("2024-01-01")])
.range([marginLeft, width - marginRight]);
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, 100])
.range([height - marginBottom, marginTop]);
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
// Add the y-axis.
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
// Return the SVG element.
return svg.node();
}
より完全な例として、これらのスターターテンプレートのいずれかを試してください。
フォーク可能な例については、D3ギャラリーを参照してください。
Observableには、セルを追加するために + をクリックしたときにいくつかのD3スニペットが含まれています(セルメニューが開いているときに「d3」と入力してフィルターします)。また、D3機能を試すための便利なサンプルデータセットも含まれています。または、CSVファイルやJSONファイルをアップロードして、データの操作を開始することもできます。また、公開済みの数百のノートブックをフォークして、スタートを切ることもできます。
Observableは、一般利用は無料です。プライベートデータベースに接続し、プライベートノートブックで共同作業を行うなどの機能を使用するには、Proアカウントにサインアップしてください。
プレーンなHTMLでのD3
プレーンなHTMLでは、jsDelivrなどのCDNからD3を読み込むか、ローカルにダウンロードできます。CDNホストのESモジュールバンドルを使用することをお勧めします。ただし、必要に応じて、プレーンなスクリプトとしてロードされるときにd3
グローバルをエクスポートするUMDバンドルも提供しています。
<!DOCTYPE html>
<div id="container"></div>
<script type="module">
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";
// Declare the chart dimensions and margins.
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
.domain([new Date("2023-01-01"), new Date("2024-01-01")])
.range([marginLeft, width - marginRight]);
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, 100])
.range([height - marginBottom, marginTop]);
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
// Add the y-axis.
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
// Append the SVG element.
container.append(svg.node());
</script>
<!DOCTYPE html>
<div id="container"></div>
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
<script type="module">
// Declare the chart dimensions and margins.
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
.domain([new Date("2023-01-01"), new Date("2024-01-01")])
.range([marginLeft, width - marginRight]);
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, 100])
.range([height - marginBottom, marginTop]);
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
// Add the y-axis.
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
// Append the SVG element.
container.append(svg.node());
</script>
<!DOCTYPE html>
<div id="container"></div>
<script src="d3.js"></script>
<script type="module">
// Declare the chart dimensions and margins.
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;
// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
.domain([new Date("2023-01-01"), new Date("2024-01-01")])
.range([marginLeft, width - marginRight]);
// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
.domain([0, 100])
.range([height - marginBottom, marginTop]);
// Create the SVG container.
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
// Add the x-axis.
svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(d3.axisBottom(x));
// Add the y-axis.
svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(d3.axisLeft(y));
// Append the SVG element.
container.append(svg.node());
</script>
次のように、個々のD3モジュールをインポートして分割することもできます。
<script type="module">
import {forceSimulation, forceCollide, forceX} from "https://cdn.jsdelivr.net/npm/d3-force@3/+esm";
const nodes = [{}, {}];
const simulation = forceSimulation(nodes)
.force("x", forceX())
.force("collide", forceCollide(5))
.on("tick", () => console.log(nodes[0].x));
</script>
D3をローカル(またはオフライン)で実行したい場合は、ここでD3のUMDバンドルをダウンロードできます。
次に、上記の UMD + ローカル タブに示されているように、index.html
ファイルを作成します。デバッグには非圧縮バンドルを使用し、本番環境でのパフォーマンスを向上させるには圧縮バンドルを使用します。
npmからインストール
Nodeを使用してWebアプリケーションを開発している場合は、yarn、npm、pnpm、または好みのパッケージマネージャーを介してD3をインストールできます。
yarn add d3
npm install d3
pnpm add d3
次に、次のようにD3をアプリにロードできます。
import * as d3 from "d3";
必要に応じて、特定のシンボルをインポートすることもできます。
import {select, selectAll} from "d3";
あるいは、D3サブモジュールからインストールしてインポートすることもできます。
import {mean, median} from "d3-array";
TypeScriptの宣言は、DefinitelyTypedを介して利用できます。
ReactでのD3
d3-scale、d3-array、d3-interpolate、d3-formatを含むほとんどのD3モジュールはDOMと相互作用しないため、Reactで使用する場合も違いはありません。以下の折れ線グラフのように、JSXで純粋に宣言型の可視化に使用できます。
import * as d3 from "d3";
export default function LinePlot({
data,
width = 640,
height = 400,
marginTop = 20,
marginRight = 20,
marginBottom = 20,
marginLeft = 20
}) {
const x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
const y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
const line = d3.line((d, i) => x(i), y);
return (
<svg width={width} height={height}>
<path fill="none" stroke="currentColor" strokeWidth="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" strokeWidth="1.5">
{data.map((d, i) => (<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />))}
</g>
</svg>
);
}
選択を操作するD3モジュール(d3-selection、d3-transition、d3-axisを含む)はDOMを操作しますが、これはReactの仮想DOMと競合します。そのような場合は、要素にrefをアタッチし、useEffectフックでD3に渡すことができます。
import * as d3 from "d3";
import {useRef, useEffect} from "react";
export default function LinePlot({
data,
width = 640,
height = 400,
marginTop = 20,
marginRight = 20,
marginBottom = 30,
marginLeft = 40
}) {
const gx = useRef();
const gy = useRef();
const x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
const y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
const line = d3.line((d, i) => x(i), y);
useEffect(() => void d3.select(gx.current).call(d3.axisBottom(x)), [gx, x]);
useEffect(() => void d3.select(gy.current).call(d3.axisLeft(y)), [gy, y]);
return (
<svg width={width} height={height}>
<g ref={gx} transform={`translate(0,${height - marginBottom})`} />
<g ref={gy} transform={`translate(${marginLeft},0)`} />
<path fill="none" stroke="currentColor" strokeWidth="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" strokeWidth="1.5">
{data.map((d, i) => (<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />))}
</g>
</svg>
);
}
ReactでのD3の使用に関する詳細については、Amelia Wattenbergerの投稿を参照してください。
SvelteでのD3
Reactと同様に、Svelteをレンダリング専用に使用し、DOMを操作しないD3モジュールのみを使用することもできます。以下は、d3-shapeとd3-scaleを使用する数値配列の折れ線グラフです。
<script>
import * as d3 from 'd3';
export let data;
export let width = 640;
export let height = 400;
export let marginTop = 20;
export let marginRight = 20;
export let marginBottom = 20;
export let marginLeft = 20;
$: x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
$: y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
$: line = d3.line((d, i) => x(i), y);
</script>
<svg width={width} height={height}>
<path fill="none" stroke="currentColor" stroke-width="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" stroke-width="1.5">
{#each data as d, i}
<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />
{/each}
</g>
</svg>
Svelteのリアクティブステートメント($:
)は、D3のデータ結合と相性が良く、効率的な更新が可能です。以下では、データが変更されるにつれて動的な軸をレンダリングするために使用しています。
<script>
import * as d3 from 'd3';
export let data;
export let width = 640;
export let height = 400;
export let marginTop = 20;
export let marginRight = 20;
export let marginBottom = 30;
export let marginLeft = 40;
let gx;
let gy;
$: x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
$: y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
$: line = d3.line((d, i) => x(i), y);
$: d3.select(gy).call(d3.axisLeft(y));
$: d3.select(gx).call(d3.axisBottom(x));
</script>
<svg width={width} height={height}>
<g bind:this={gx} transform="translate(0,{height - marginBottom})" />
<g bind:this={gy} transform="translate({marginLeft},0)" />
<path fill="none" stroke="currentColor" stroke-width="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" stroke-width="1.5">
{#each data as d, i}
<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />
{/each}
</g>
</svg>