入门
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 中,您可以从 CDN(如 jsDelivr)加载 D3,也可以在本地下载。我们建议使用 CDN 托管的 ES 模块捆绑包。但是,对于那些需要它的人,我们还提供了一个 UMD 捆绑包,该捆绑包在作为普通脚本加载时会导出 d3
全局变量。
<!DOCTYPE html>
<div id="container"></div>
<script type="module">
import * as d3 from "https://cdn.jsdelivr.net.cn/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.cn/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.cn/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 捆绑包
然后,创建一个 index.html
文件,如上面UMD + 本地选项卡中所示。使用非压缩捆绑包进行调试,并使用压缩捆绑包在生产中获得更快的性能。
从 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 模块(包括 d3-scale、d3-array、d3-interpolate 和 d3-format)不会与 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>