mirror of
https://github.com/d3/d3.git
synced 2025-12-08 19:46:24 +00:00
423 lines
13 KiB
Markdown
423 lines
13 KiB
Markdown
<script setup>
|
||
|
||
import ExampleBlankChart from "./components/ExampleBlankChart.vue";
|
||
|
||
</script>
|
||
|
||
# Getting started
|
||
|
||
D3 works in any JavaScript environment.
|
||
|
||
## Try D3 online
|
||
|
||
The fastest way to get started (and get help) with D3 is on [Observable](https://observablehq.com)! D3 is available by default in notebooks as part of Observable’s standard library. To create something with D3, return the generated DOM element from a cell. Here is a blank chart to get you started:
|
||
|
||
<ExampleBlankChart />
|
||
|
||
```js
|
||
{
|
||
// 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();
|
||
}
|
||
```
|
||
|
||
As a more complete example, try one of these starter templates:
|
||
|
||
* [Area chart](https://observablehq.com/@d3/area-chart/2?intent=fork)
|
||
* [Bar chart](https://observablehq.com/@d3/bar-chart/2?intent=fork)
|
||
* [Donut chart](https://observablehq.com/@d3/donut-chart/2?intent=fork)
|
||
* [Histogram](https://observablehq.com/@d3/histogram/2?intent=fork)
|
||
* [Line chart](https://observablehq.com/@d3/line-chart/2?intent=fork)
|
||
|
||
See the [D3 gallery](https://observablehq.com/@d3/gallery) for more forkable examples.
|
||
|
||
Observable includes a few D3 snippets when you click **+** to add a cell (type “d3” when the cell menu is open to filter), as well as convenient [sample datasets](https://observablehq.com/@observablehq/sample-datasets) to try out D3 features. Or upload a CSV or JSON file to start playing with your data. You can also fork any of the [hundreds of notebooks](https://observablehq.com/@d3?tab=notebooks) we’ve published for a head start.
|
||
|
||
Observable is free for public use. Sign up for a [Pro account](https://observablehq.com/pricing) to connect to private databases, collaborate on private notebooks, and more.
|
||
|
||
## D3 in vanilla HTML
|
||
|
||
In vanilla HTML, you can load D3 from a CDN such as jsDelivr or you can download it locally. We recommend using the CDN-hosted ES module bundle. But for those who need it, we also provide a UMD bundle that exports the `d3` global when loaded as a plain script.
|
||
|
||
:::code-group
|
||
```html [ESM + CDN]
|
||
<!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>
|
||
```
|
||
|
||
```html [UMD + CDN]
|
||
<!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>
|
||
```
|
||
|
||
```html [UMD + local]
|
||
<!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>
|
||
```
|
||
:::
|
||
|
||
You can also import and destructure individual D3 modules like so:
|
||
|
||
```html
|
||
<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>
|
||
```
|
||
|
||
If you’d prefer to run D3 locally (or offline), you can download the UMD bundles of D3 here:
|
||
|
||
- <a href="./d3.v7.js" download>d3.v7.js</a>
|
||
- <a href="./d3.v7.min.js" download>d3.v7.min.js</a>
|
||
|
||
Then, create an `index.html` file as shown above in the **UMD + local** tab. Use the non-minified bundle for debugging, and the minified bundle for faster performance in production.
|
||
|
||
## Installing from npm
|
||
|
||
If you’re developing a web application using Node, you can install D3 via yarn, npm, pnpm, or your preferred package manager.
|
||
|
||
:::code-group
|
||
|
||
```bash [yarn]
|
||
yarn add d3
|
||
```
|
||
|
||
```bash [npm]
|
||
npm install d3
|
||
```
|
||
|
||
```bash [pnpm]
|
||
pnpm add d3
|
||
```
|
||
|
||
:::
|
||
|
||
You can then load D3 into your app as:
|
||
|
||
```js
|
||
import * as d3 from "d3";
|
||
```
|
||
|
||
You can instead import specific symbols if you prefer:
|
||
|
||
```js
|
||
import {select, selectAll} from "d3";
|
||
```
|
||
|
||
Alternatively you can install and import from D3 submodules:
|
||
|
||
```js
|
||
import {mean, median} from "d3-array";
|
||
```
|
||
|
||
TypeScript declarations are available via [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped).
|
||
|
||
## D3 in React
|
||
|
||
Most D3 modules (including [d3-scale](./d3-scale.md), [d3-array](./d3-array.md), [d3-interpolate](./d3-interpolate.md), and [d3-format](./d3-format.md)) don’t interact with the DOM, so there is no difference when using them in React. You can use them in JSX for purely declarative visualization, such as the line plot below.
|
||
|
||
:::code-group
|
||
```jsx [LinePlot.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>
|
||
);
|
||
}
|
||
```
|
||
:::
|
||
|
||
<p style="margin-top: -1em;"><a href="https://codesandbox.io/s/d3-react-ssr-5g1bm0?file=/src/LinePlot.jsx" style="font-size: smaller;" target="_blank">Sandbox ↗︎</a></p>
|
||
|
||
D3 modules that operate on [selections](./d3-selection/selecting.md) (including [d3-selection](./d3-selection.md), [d3-transition](./d3-transition.md), and [d3-axis](./d3-axis.md)) do manipulate the DOM, which competes with React’s virtual DOM. In those cases, you can attach a ref to an element and pass it to D3 in a useEffect hook.
|
||
|
||
:::code-group
|
||
```jsx [LinePlot.jsx]
|
||
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>
|
||
);
|
||
}
|
||
```
|
||
:::
|
||
|
||
<p style="margin-top: -1em;"><a href="https://codesandbox.io/s/d3-react-useeffect-5lp0x6?file=/src/LinePlot.jsx" style="font-size: smaller;" target="_blank">Sandbox ↗︎</a></p>
|
||
|
||
For more guidance using D3 in React, see [Amelia Wattenberger’s post](https://2019.wattenberger.com/blog/react-and-d3).
|
||
|
||
## D3 in Svelte
|
||
|
||
As [with React](#d3-in-react), you can use Svelte exclusively for rendering if you like, and only use D3 modules that don’t manipulate the DOM. Here is a line plot of an array of numbers that uses [d3-shape](./d3-shape.md) and [d3-scale](./d3-scale-chromatic.md).
|
||
|
||
:::code-group
|
||
```svelte [LinePlot.svelte]
|
||
<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>
|
||
```
|
||
:::
|
||
|
||
<p style="margin-top: -1em;"><a href="https://svelte.dev/repl/ece91c0d8b204d5ea970dbbc0d6783aa?version=3.59.1" style="font-size: smaller;" target="_blank">REPL ↗︎</a></p>
|
||
|
||
Svelte’s reactive statements (`$:`) pair nicely with D3 [data joins](./d3-selection/joining.md) for efficient updates. Below, we use them to render dynamic axes as the data changes.
|
||
|
||
:::code-group
|
||
```svelte [LinePlot.svelte]
|
||
<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>
|
||
```
|
||
:::
|
||
|
||
<p style="margin-top: -1em;"><a href="https://svelte.dev/repl/ff3bf3c7ca454d53913c0c33af0c1250?version=3.59.1" style="font-size: smaller;" target="_blank">REPL ↗︎</a></p>
|