1
0
mirror of https://github.com/d3/d3.git synced 2025-12-08 19:46:24 +00:00
d3/docs/getting-started.md
2024-04-25 14:42:03 +00:00

423 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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 Observables 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) weve 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 youd 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 youre 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)) dont 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 Reacts 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 Wattenbergers 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 dont 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>
Sveltes 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>