# https://www.d3indepth.com/ llms-full.txt

## Master D3.js Visualization
Learn D3.js from the ground up

## D3.js Getting Started
# Getting Started

_Getting started with D3.js. This article assumes familiarity with HTML, SVG, CSS and JavaScript._

D3 in Depth assumes you're familiar with HTML, SVG, CSS and JavaScript. If not, I recommend reading [Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualisation](https://leanpub.com/html-svg-css-js-for-data-visualisation/).

If you're familiar with libraries such as React and Vue.js (or even jQuery) you should be fine.

### CodePen examples [Anchor link for: codepen examples](https://www.d3indepth.com/gettingstarted/\#codepen-examples)

D3 in Depth uses CodePen to demonstrate code. Here's an example:

Click the 'Edit in CodePen' button to open the example in CodePen.

Each example consists of three or more files:

- `index.html`
- `index.js`
- `style.css`

`index.html` usually looks similar to:

```html
<svg width="760" height="140">
  <g transform="translate(70, 70)">
  </g>
</svg>
```

`index.js` contains the JavaScript code and `style.css` contains CSS code.

### Developing with bundlers [Anchor link for: developing with bundlers](https://www.d3indepth.com/gettingstarted/\#developing-with-bundlers)

If you're using a bundler such as Vite or Webpack import D3 modules using code similar to:

```js
import { select } from 'd3-selection';
```

Note the Codepen examples use [Skypack](https://www.skypack.dev/) so the equivalent import is:

```js
import { select } from 'https://esm.sh/d3-selection';
```

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## Introduction to D3.js
# Introduction to D3.js

_An introduction and overview of the D3.js data visualisation library._

[D3](https://d3js.org/) is a JavaScript library used to create **bespoke**, **interactive** charts and maps on the web.

Most charting libraries (such as [Chart.js](https://chartjs.org/) and [Highcharts](https://www.highcharts.com/)) provide ready made charts whereas D3 consists of **building blocks** with which custom charts or maps can be constructed.

D3's approach is much lower level than other charting libraries. Creating a bar chart with Chart.js is just a [few lines of code](https://codepen.io/createwithdata/pen/axgoaQ).

![chart.js example](https://www.d3indepth.com/img/chartjs-example.png)

Creating a similar chart with D3 is more involved and requires experience with **JavaScript**, **HTML**, **SVG** and **CSS**.

If you require a standard bar, line or pie chart you should consider a library such as [Chart.js](https://chartjs.org/). However if you require bespoke charts or have very precise needs then D3 should be considered.

D3's features include:

- data-driven modification of HTML and SVG elements
- scale functions
- loading and transforming data (e.g. CSV data)
- helpers for generating complex charts such as treemaps, packed circles and networks
- a powerful transition system for animating between different chart states
- powerful user interaction support, including panning, zooming and dragging

Let's look at each of these in turn.

## Data-driven modification of HTML/SVG elements [Anchor link for: data driven modification of html svg elements](https://www.d3indepth.com/introduction/\#data-driven-modification-of-html-svg-elements)

D3 lets you add, remove and modify HTML and SVG elements in a **data-driven** fashion.

For example, suppose you have an array of numbers. You can ask D3 to create an SVG circle for each array element.

Furthermore you can ask D3 to set the radius of each circle according to each array value. This is known as **data binding** (or **joining**) and is a cornerstone of D3.

We cover these aspects in the [Selections](https://www.d3indepth.com/selections), [Joins](https://www.d3indepth.com/datajoins) and [Enter/Exit](https://www.d3indepth.com/enterexit) chapters.

## Scale functions [Anchor link for: scale functions](https://www.d3indepth.com/introduction/\#scale-functions)

Scale functions take an input (usually a number, string or date) and return a value (usually a number or a string).

They’re typically used to transform (or 'map') **data** values into **visual** values (such as position, length and colour).

For example, they can be used to transform your data values into positions on the screen.

Scale functions are covered in the [Scale functions](https://www.d3indepth.com/scales) chapter.

## Loading and transforming data [Anchor link for: loading and transforming data](https://www.d3indepth.com/introduction/\#loading-and-transforming-data)

One of the most common data formats is comma separated value (CSV). This format is easily exportable by spreadsheets and databases, is human readable and is relatively compact.

D3 can help you request CSV files from a given URL and to convert the CSV file into a JavaScript array. This makes working with real data much easier.

We cover loading CSV files in the [Requests](https://www.d3indepth.com/requests) chapter.

## Complex chart creation [Anchor link for: complex chart creation](https://www.d3indepth.com/introduction/\#complex-chart-creation)

D3 provides building blocks for creating more complex charts such as **treemaps**, **packed circles**, **network graphs** and **geographic maps**.

For example, to create a packed circle chart you can use D3's pack layout which, given a tree data structure, appends position and size values to each item in the tree.

You can then use a D3 data join to create an SVG circle for each tree item. Each circle can then be positioned and sized according to the values calculated by the pack layout.

![Packed circles](https://www.d3indepth.com/img/layouts/pack.png)

We cover the creation of more complex shapes and charts in the [Shapes](https://www.d3indepth.com/shapes), [Layouts](https://www.d3indepth.com/layouts), [Force](https://www.d3indepth.com/force-layout) and [Geographic](https://www.d3indepth.com/geographic) chapters.

## Transitions [Anchor link for: transitions](https://www.d3indepth.com/introduction/\#transitions)

D3 transitions let you smoothly animate between different chart states. For instance, if you have a scatter plot and the user selects a different indicator for one of the axes, the points will smoothly animate to their new positions.

![Transitions](https://www.d3indepth.com/img/introduction/transitions.gif)

As well as being visually appealing, the transition helps you track the movement of the points.

D3's transition system is powerful (it lets you control how elements first appear, how they move to new states, and how they exit the page) and is relatively simple to use.

We cover D3 transitions in the [Transitions](https://www.d3indepth.com/transitions) chapter.

## Advanced interaction support [Anchor link for: advanced interaction support](https://www.d3indepth.com/introduction/\#advanced-interaction-support)

When the entire contents of a chart or map can't comfortably fit within a given window, user interaction such as panning and zooming can help.

D3 can help you add panning and zooming to a chart, saving you a lot of work (especially checking it works on all platforms).

We cover advanced interactions in the [Interaction](https://www.d3indepth.com/interaction) chapter.

## Where next? [Anchor link for: where next](https://www.d3indepth.com/introduction/\#where-next)

Unless you're here for a specific topic, I suggest starting with the [Selections](https://www.d3indepth.com/selections), [Joins](https://www.d3indepth.com/datajoins), [Enter/exit](https://www.d3indepth.com/enterexit) and [Scales](https://www.d3indepth.com/scales) chapters.

Once you're comfortable with those, browse through the remaining chapters and choose whichever appeals the most!

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Selections Guide
# D3 Selections

_How to select HTML and SVG elements using D3 selections. This article shows how to select, insert, remove and modify elements, how to add event handlers, how to apply a function to selections and how to filter and sort selections._

D3 selections let you choose some HTML or SVG elements and change their style and/or attributes.

For example, if your `index.html` file contains 5 SVG circle elements:

```html
<svg width="760" height="140">
  <g transform="translate(70, 70)">
    <circle/>
    <circle cx="120" />
    <circle cx="240" />
    <circle cx="360" />
    <circle cx="480" />
  </g>
</svg>
```

you can use `selectAll` to select the circles then `.style` to change their fill and `.attr` to change their radius:

```js
selectAll('circle')
  .style('fill', 'orange')
  .attr('r', function() {
    return 10 + Math.random() * 40;
  });
```

D3 selections also enable data joins (see the [Data Joins](https://www.d3indepth.com/datajoins) chapter).

### Making selections [Anchor link for: making selections](https://www.d3indepth.com/selections/\#making-selections)

The D3 module `d3-selection` provides two functions `select` and `selectAll`.

To import `select` use:

```js
import { select } from 'd3-selection';
```

To import `selectAll` use:

```js
import { selectAll } from 'd3-selection';
```

Import both using:

```js
import { select, selectAll } from 'd3-selection';
```

`select` selects the first matching element whilst `selectAll` selects all matching elements.

Both functions take a string as its only argument. The string specifies which elements to select and is in the form of a CSS selector string. For example:

- `div.item`
- `#my-chart`
- `g:first-child`

For example to select all elements with class `item` use:

```js
selectAll('.item')
```

(If you’re not familiar with CSS selectors take a look at the CSS section in [Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualization](https://leanpub.com/html-svg-css-js-for-data-visualisation/).)

### Modifying elements [Anchor link for: modifying elements](https://www.d3indepth.com/selections/\#modifying-elements)

You can modify a selection's elements using the following methods:

| Name | Behaviour | Example |
| --- | --- | --- |
| `.style` | Update the style | `selectAll('circle').style('fill', 'red')` |
| `.attr` | Update an attribute | `selectAll('rect').attr('width', 10)` |
| `.classed` | Add/remove a class attribute | `select('.item').classed('selected', true)` |
| `.property` | Update an element's property | `selectAll('.checkbox').property('checked', false)` |
| `.text` | Update the text content | `select('div.title').text('My new book')` |
| `.html` | Change the html content | `select('.legend').html('<div class="block"></div><div>0 - 10</div>')` |

Note that the second argument of `.classed` is a boolean. I often forget to include `true` or `false` and it raises an non-obvious error message!

Here's an example of all of these functions in use:

D3 in Depth selection example

A checkbox


### Updating selections with functions [Anchor link for: updating selections with functions](https://www.d3indepth.com/selections/\#updating-selections-with-functions)

You can also pass a function into a selection method. For example:

```js
selectAll('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  });
```

The function accepts two arguments. The first argument (usually named `d`) is the **joined data** (or 'datum') and will be covered in the [data joins chapter](https://www.d3indepth.com/datajoins). The second argument (usually named `i`) is the **index** of the element within the selection.

To update elements in a selection according to their position within the selection use the `i` argument. For example to position `rect` elements horizontally use:

```js
selectAll('rect')
  .attr('x', function(d, i) {
    return i * 40;
  });
```

Click to update rect elements using function(d, i)

In the majority of cases anonymous functions are passed into selection methods. However you may altenatively use named functions. For example:

```js
function positionRects(d, i) {
  return i * 40;
}

selectAll('rect')
  .attr('x', positionRects);
```

### Event handling [Anchor link for: event handling](https://www.d3indepth.com/selections/\#event-handling)

You can add an event handler to a selection using the `.on` method.

This method has two arguments:

- the first is a string specifying the event type

- the second is a function (a 'callback function') that's called when the event is triggered. This callback function has two arguments that are usually named `e` and `d`. `e` is the DOM event object and `d` is the joined data (which will be covered in the [data joins chapter](https://www.d3indepth.com/datajoins)).


> Up to and including D3 version 5, the callback function was passed the datum `d` and index `i`. This is a **breaking change**.

The most common events include:

| Event name | Description |
| --- | --- |
| `click` | Element has been clicked |
| `mouseenter` | Mouse pointer has moved onto the element |
| `mouseover` | Mouse pointer has moved onto the element or its children |
| `mouseleave` | Mouse pointer has moved off the element |
| `mouseout` | Mouse pointer has moved off the element or its children |
| `mousemove` | Mouse pointer has moved over the element |

See [MDN event reference](https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events) for more details.

In the event callback function the `this` variable is bound to the DOM element that triggered the event. This allows us to do things such as:

```js
selectAll('circle')
  .on('click', function(e, d) {
    select(this)
      .style('fill', 'orange');
  });
```

Click on a circle

Note that `this` is a DOM element and not a D3 selection so if you wish to modify it using D3 you must first select it using `select(this)`.

Note also that D3 does not define `this` for arrow functions.

### Inserting and removing elements [Anchor link for: inserting and removing elements](https://www.d3indepth.com/selections/\#inserting-and-removing-elements)

Elements can be added to a selection's elements using `.append` and `.insert`. Elements can be removed using `.remove`.

`.append` appends an element to each element in a selection. If the elements already have children, the new element will become the last child. The first argument specifies the type of element.

As an example let's start with 3 `g` elements, each containing a `circle`:

```html
<g class="item" transform="translate(0, 0)">
  <circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
  <circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
  <circle r="40" />
</g>
```

Append a `text` element to each using:

```js
selectAll('g.item')
  .append('text')
  .text('A');
```

This results in a `text` element being added to each `g.item`:

```html
<g class="item" transform="translate(0, 0)">
  <circle r="40" />
  <text>A</text>
</g>
<g class="item" transform="translate(120, 0)">
  <circle r="40" />
  <text>A</text>
</g>
<g class="item" transform="translate(240, 0)">
  <circle r="40" />
  <text>A</text>
</g>
```

AAA

`.insert` is similar to `.append` but it lets us provide a CSS selector string as the second argument. This specifies an element before which the new element is inserted.

In this example, `.insert` is used and the second argument is `'circle'`:

```js
selectAll('g.item')
  .insert('text', 'circle')
  .text('A');
```

This results in the text element being inserted before the circle:

```html
<g class="item" transform="translate(0, 0)">
  <text>A</text>
  <circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
  <text>A</text>
  <circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
  <text>A</text>
  <circle r="40" />
</g>
```

AAA

`.remove` removes all the elements in a selection from the page. For example, given some circles, you can remove them using:

```js
selectAll('circle')
  .remove();
```

Remove circles

### Chaining [Anchor link for: chaining](https://www.d3indepth.com/selections/\#chaining)

The return value of most selection methods is the selection itself. This means that selection methods such as `.style` and `.attr` can be chained. For example:

```js
selectAll('circle')
  .style('fill', '#333')
  .attr('r', 20)
  .on('click', function(d, i) {
    select(this)
      .style('fill', 'orange');
  });
```

Click on a circle

### .each() [Anchor link for: each](https://www.d3indepth.com/selections/\#each)

The `.each` method lets you call a function for **each element of a selection**.

The callback function has two arguments usually named `d` and `i`. The first argument `d` is the **joined data** (or 'datum') and will be covered in the [data joins chapter](https://www.d3indepth.com/datajoins). `i` is the **index** of the element within the selection. The `this` keyword refers to the current HTML or SVG element in the selection.

Here's an example where `.each` is used to call a function for each of the selection's elements. The function computes whether the index is odd or even and modifies the circle accordingly:

```js
selectAll('circle')
  .each(function(d, i) {
    let odd = i % 2 === 1;

    select(this)
      .style('fill', odd ? 'orange' : '#ddd')
      .attr('r', odd ? 40 : 20);
  });
```

Note that `this` refers to the current HTML or SVG element (or the `i` th element in the selection). If you wish to modify it using D3 you can select it using `select(this)`.

### .call() [Anchor link for: call](https://www.d3indepth.com/selections/\#call)

The `.call` method allows a function to be called into which the **selection itself** is passed as the first argument.

`.call` is useful where you want a reusable function that operates on a selection.

For example, `colorAll` takes a selection and sets the fill of the selection's elements to orange:

```js
function colorAll(selection) {
  selection
    .style('fill', 'orange');
}

selectAll('circle')
  .call(colorAll);
```

### Filtering and sorting selections [Anchor link for: filtering and sorting selections](https://www.d3indepth.com/selections/\#filtering-and-sorting-selections)

You can filter a selection using D3's `.filter` method. The first argument is a function which returns `true` if the element should be included. The filtered selection is returned by the `filter` method so you can continue chaining selection methods.

Thie example filters for even-numbered elements and colours them orange:

```js
selectAll('circle')
  .filter(function(d, i) {
    return i % 2 === 0;
  })
  .style('fill', 'orange');
```

Sorting only really makes sense if data has been joined to the selection so knowledge of [data joins](https://www.d3indepth.com/datajoins) is helpful.

You can sort elements in a selection by calling `.sort` and passing in a comparator function. The comparator function has two arguments, usually `a` and `b`, which represent the datums on the two elements being compared. If the comparator function returns a negative number, `a` will be placed before `b` and if positive, `a` will be placed after `b`.

Thus if you have the following data joined to a selection:

```json
[\
  {\
    "name": "Andy",\
    "score": 37\
  },\
  {\
    "name": "Beth",\
    "score": 39\
  },\
  {\
    "name": "Craig",\
    "score": 31\
  },\
  {\
    "name": "Diane",\
    "score": 35\
  },\
  {\
    "name": "Evelyn",\
    "score": 38\
  }\
]
```

you can sort by `score` using:

```js
  selectAll('.person')
    .sort(function(a, b) {
      return b.score - a.score;
    });
```

Andy

Beth

Craig

Diane

Evelyn

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Data Joins
# D3 Data Joins

_This article shows how to join an array of data to a D3 selection. We cover how to create a data join, how to update a data join, how to join an array of objects and key functions._

A data join creates a correspondence between an array of data and a selection of HTML or SVG elements.

Joining an array to HTML/SVG elements means that:

- HTML (or SVG) elements are added or removed such that **each array element has a corresponding HTML (or SVG) element**
- each HTML/SVG element may be **positioned, sized and styled** according to the value of its corresponding array element

For example, suppose we've an array of five numbers which we'd like to join to `circle` elements:

```js
[ 40, 10, 20, 60, 30 ]
```

Each time D3 performs the join it adds or removes `circle` elements so that each array element has a corresponding `circle` element.

D3 can also update the position and radius of each circle (and any other attributes or style) based on the value of the corresponding array element.

For example, the radius of each circle can be set to half the value of the corresponding array value. This results in the first circle having a radius of 20, the second a radius of 5 and so on:

Prior to version 5 of D3, data joins were not all that easy to learn (you had to learn about enter, exit and update). Fortunately, for versions 5 and up, data joins are much easier!

## How to create a data join [Anchor link for: how to create a data join](https://www.d3indepth.com/datajoins/\#how-to-create-a-data-join)

The general pattern for creating a data join is:

```js
select(container)
  .selectAll(element-type)
  .data(array)
  .join(element-type);
```

where:

- `container` is a CSS selector string that specifies a **single element** that'll contain the joined HTML/SVG elements
- `element-type` is a string describing the **type of element** you’re joining (e.g. ‘div' or 'circle')
- `array` is the name of **the array** you’re joining

Typically four methods are used in a data join:

- `.select` defines the element that'll act as a container (or parent) to the joined HTML/SVG elements
- `.selectAll` defines the type of element that'll be joined to each array element
- `.data` defines the array that's being joined
- `.join` performs the join. This is where HTML or SVG elements are added and removed

### Example [Anchor link for: example](https://www.d3indepth.com/datajoins/\#example)

Given an array:

```js
let myData = [40, 10, 20, 60, 30];
```

and an `svg` element containing a `g` element:

```html
<svg>
  <g class="chart">
  </g>
</svg>
```

join `myData` to `circle` elements using:

```js
let myData = [40, 10, 20, 60, 30];

select('.chart')
  .selectAll('circle')
  .data(myData)
  .join('circle');
```

In this example:

- the container is the `g` element
- the element type is `circle`
- the array being joined is `myData`

Running this code results in 5 circles being created:

```html
<svg>
  <g class="chart">
    <circle></circle>
    <circle></circle>
    <circle></circle>
    <circle></circle>
    <circle></circle>
  </g>
</svg>
```

You can't see any circles because each radius is zero. However if you inspect and expand the SVG element (right click on the SVG element which has been coloured light pink and select Inspect) you'll see five `circle` elements have been added:

![5 circles added to DOM](https://www.d3indepth.com/img/datajoins/5circles.png)

In the CodePen example you can try adding elements to the array and you'll see that the data join ensures there are as many circles as array elements.

### Updating the joined elements [Anchor link for: updating the joined elements](https://www.d3indepth.com/datajoins/\#updating-the-joined-elements)

Joined HTML or SVG elements may be updated using the `.style`, `.attr` and `.text` methods that were covered in the [selections](https://www.d3indepth.com/selections) chapter.

For example you can set the center, radius and colour of every circle using:

```js
let myData = [40, 10, 20, 60, 30];

select('.chart')
  .selectAll('circle')
  .data(myData)
  .join('circle')
  .attr('cx', 200)
  .attr('cy', 50)
  .attr('r', 40)
  .style('fill', 'orange');
```

You only see one circle because all five circles share the same position and size.

### Data driven updates [Anchor link for: data driven updates](https://www.d3indepth.com/datajoins/\#data-driven-updates)

If a **function** is passed into `.attr` or `.style` you can update the HTML/SVG elements in a **data-driven** manner.

The function is called for **each element in the selection**. It takes two parameters, typically named `d` and `i`.

The first parameter ( `d`) represents the corresponding array element (or the 'joined value'). The second parameter `i` represents the index of the element within the selection.

The return value of the function is used to set the attribute or style value.

Let's pass a function into the first `.attr`:

```js
let myData = [40, 10, 20, 60, 30];

select('.chart')
  .selectAll('circle')
  .data(myData)
  .join('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  })
  .attr('cy', 50)
  .attr('r', 40)
  .style('fill', 'orange');
```

This tells D3 to set each circle's `cx` attribute to `i * 100`. `i` is the index within the selection, so the first circle will be positioned at `0`, the next at `100` and so on:

Now let's set `r` according to the joined value:

```js
let myData = [40, 10, 20, 60, 30];

select('.chart')
  .selectAll('circle')
  .data(myData)
  .join('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  })
  .attr('cy', 50)
  .attr('r', function(d) {
    return 0.5 * d;
  })
  .style('fill', 'orange');
```

(The first circle is clipped because it's `cx` attribute is zero.)

You can put any amount of logic within the functions that are passed into `.attr` and `.style`. For example, let's colour the circle if its joined value is greater than 30:

```js
let myData = [40, 10, 20, 60, 30];

select('.chart')
  .selectAll('circle')
  .data(myData)
  .join('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  })
  .attr('cy', 50)
  .attr('r', function(d) {
    return 0.5 * d;
  })
  .style('fill', function(d) {
    return d > 30 ? 'orange' : '#eee';
  });
```

### Joining arrays of objects [Anchor link for: joining arrays of objects](https://www.d3indepth.com/datajoins/\#joining-arrays-of-objects)

When building data visualisations with D3 arrays of objects (rather than numbers) are typically joined to selections. For example:

```js
let cities = [\
  { name: 'London', population: 8674000},\
  { name: 'New York', population: 8406000},\
  { name: 'Sydney', population: 4293000},\
  { name: 'Paris', population: 2244000},\
  { name: 'Beijing', population: 11510000}\
];
```

You can join an array of objects in the same manner as before. However, when a function is passed into `.attr` or `.style`, the `d` parameter is an object. This means you need to reference a **property** of that object.

For example:

```js
  ...
  .attr('r', function(d) {
    return 0.0001 * d.population;
  })
  ...
```

Here's a full example where `cities` is joined to `circle` elements:

```js
let cities = [\
  { name: 'London', population: 8674000},\
  { name: 'New York', population: 8406000},\
  { name: 'Sydney', population: 4293000},\
  { name: 'Paris', population: 2244000},\
  { name: 'Beijing', population: 11510000}\
];

select('.chart')
  .selectAll('circle')
  .data(cities)
  .join('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  })
  .attr('cy', 50)
  .attr('r', function(d) {
    let scaleFactor = 0.00004;
    return scaleFactor * d.population;
  })
  .style('fill', '#aaa');
```

Each circle is sized according to the city's population. (Note that it's better practice to set the area, rather than the radius, of a circle proportionally to a data value.)

You can build a simple bar chart using the above techniques. Instead of joining `circle` elements, let's join `rect` and `text` elements:

```js
let cities = [\
  { name: 'London', population: 8674000},\
  { name: 'New York', population: 8406000},\
  { name: 'Sydney', population: 4293000},\
  { name: 'Paris', population: 2244000},\
  { name: 'Beijing', population: 11510000}\
];

// Join cities to rect elements and modify height, width and position
select('.bars')
  .selectAll('rect')
  .data(cities)
  .join('rect')
  .attr('height', 19)
  .attr('width', function(d) {
    let scaleFactor = 0.00004;
    return d.population * scaleFactor;
  })
  .attr('y', function(d, i) {
    return i * 20;
  })

// Join cities to text elements and modify content and position
select('.labels')
  .selectAll('text')
  .data(cities)
  .join('text')
  .attr('y', function(d, i) {
    return i * 20 + 13;
  })
  .text(function(d) {
    return d.name;
  });
```

LondonNew YorkSydneyParisBeijing

How about that? We've just built a simple bar chart using D3!

(This example relies on extra code in `index.html` and `style.css`. Open the CodePen example to see the full example.)

## Update functions [Anchor link for: update functions](https://www.d3indepth.com/datajoins/\#update-functions)

If your data array changes **you need to perform the join again**. (Unlike some frameworks such as Vue.js, D3 doesn't automatically do this for you.)

Therefore we usually put the join code in a function. Whenever the data changes, we call this function.

For example:

```js
let myData = [40, 10, 20, 60, 30];

function update(data) {
  select('.chart')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d, i) {
      return i * 100;
    })
    .attr('cy', 50)
    .attr('r', function(d) {
      return 0.5 * d;
    })
    .style('fill', function(d) {
      return d > 30 ? 'orange' : '#eee';
    });
}

update(myData);
```

We pass the data array into `update`. Each time `update` is called the join is performed.

The data doesn't ever change in the previous example, so let's add a button that when clicked gets some randomised data and calls `update`:

```js
function getData() {
  let data = [];
  let numItems = Math.ceil(Math.random() * 5);

  for(let i=0; i<numItems; i++) {
    data.push(Math.random() * 60);
  }

  return data;
}

function update(data) {
  select('.chart')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d, i) {
      return i * 100;
    })
    .attr('cy', 50)
    .attr('r', function(d) {
      return 0.5 * d;
    })
    .style('fill', function(d) {
      return d > 30 ? 'orange' : '#eee';
    });
}

function updateAll() {
  let myData = getData();
  update(myData);
}

updateAll();

select("button")
  .on("click", updateAll);
```

Update

`getData` returns a random length array containing random values. A `button` element has been added to `index.html`. The last two lines add an event handler `updateAll` to this button. `updateAll` calls `getData` and then calls `update` to perform the join.

Each time the button is clicked the data updates and the circles update accordingly.

### Key functions [Anchor link for: key functions](https://www.d3indepth.com/datajoins/\#key-functions)

When D3 performs a data join it joins the first array element to the first element in the selection, the second array element to the second element in the selection and so on.

However if the data is re-joined and it has changed order, the array elements will be joined **to different DOM elements**. This can cause unwanted behaviour when transitions are used.

You can ensure each array element remains joined to the same HTML/SVG element by passing a **key function** into the `.data` method. The key function should return a **unique id value** for each array element.

Look at this example where an array `['Z']` is joined to `div` elements. Each time the button is clicked a new letter is added to the start of the array:

Z

Insert element

When 'Insert element' is clicked a new `div` element is added to the end of the row. However, the text of each existing `div` changes.

If a key function is used, each letter will stay joined to the same `div` element and the elements shuffle along in the expected manner:

Z

Insert element

### Debugging [Anchor link for: debugging](https://www.d3indepth.com/datajoins/\#debugging)

When D3 performs a data join it adds an attribute `data` to each DOM element in the selection and assigns the joined data to it.

You can inspect this in Google Chrome by right clicking on an element, choosing 'Inspect' and typing:

```js
$0.__data__
```

in the debug console. ( `$0` represents the element that's being inspected.)

![Inspecting data](https://www.d3indepth.com/img/datajoins/inspect_data.gif)

Being able to check the joined data in this manner is particularly useful when debugging because it lets us check whether our data join is behaving as expected.

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Enter and Exit
# D3 Enter, Exit and Update

_This article shows how D3's enter and exit methods can be used to achieve fine grained control over the behaviour of entering and exiting elements. This is particularly useful when dealing with transitioning elements._

This page explains how to gain extra control over HTML and SVG elements when they are created, updated or removed. It's particularly useful when you're using [transitions](https://www.d3indepth.com/transitions) and want particular effects (such as elements fading in and out).

Whenever you perform a data join, D3 adds or removes HTML/SVG elements in order to make the selection the same length as the data array. HTML/SVG elements that are added are known as **entering** elements and elements that are removed are known as **exiting** elements.

In some instances it's useful to treat entering and exiting elements differently. For example, you might want entering elements to fade in and exiting elements to fade out.

You can define the behaviour of entering and exiting elements by passing functions into the `.join` method:

```js
.join(
  function(enter) {
    ...
  },
  function(update) {
    ...
  },
  function(exit) {
    ...
  }
)
```

The first, second and third functions are the **enter**, **update** and **exit** functions, respectively.

Each function has a single parameter:

- the enter function's parameter is the **enter selection** which represents the elements that need to be created
- the update function's parameter is a selection containing the elements that are already in existence (and aren't exiting)
- the exit function's parameter is the **exit selection** and contains elements that need to to be removed

The `.join` method returns a selection containing the **entering and existing elements** (it doesn't contain exiting elements). Typically most of your style and attribute updates will follow the `.join` method.

Note that the enter, update and exit functions **must return the selection**.

### Enter function [Anchor link for: enter function](https://www.d3indepth.com/enterexit/\#enter-function)

In general the enter function must append an element to each element of the enter selection. (The enter selection consists of 'placeholder' elements that represent the elements that need to be added.)

For example:

```js
.join(
  function(enter) {
    return enter.append('circle');
  }
)
```

You can also call the usual selection methods such as `.style` and `.attr` on the enter selection. This allows you to modify style and attributes of the entering elements. This is typically used to initialise entering elements prior to transitioning them to their joined value.

For example, if you want elements to fade in, set their opacity to zero:

```js
.join(
  function(enter) {
    return enter
      .append('circle')
      .style('opacity', 0);
  }
)
```

### Update function [Anchor link for: update function](https://www.d3indepth.com/enterexit/\#update-function)

The update function is optional and lets you update elements that are **already in existence**. For example:

```js
.join(
  function(enter) {
    return enter
      .append('circle')
      .style('opacity', 0);
  },
  function(update) {
    return update.style('opacity', 1);
  }
)
```

This will set the opacity of entering circles to zero and the opacity of existing circles to 1.

### Exit function [Anchor link for: exit function](https://www.d3indepth.com/enterexit/\#exit-function)

The exit function is optional and handles HTML/SVG elements that **need to be removed**. In general you need to remove the elements in the exit selection:

```js
.join(
  function(enter) {
    return enter
      .append('circle')
      .style('opacity', 0);
  },
  function(update) {
    return update
      .style('opacity', 1);
  },
  function(exit) {
    return exit.remove();
  }
)
```

## Example [Anchor link for: example](https://www.d3indepth.com/enterexit/\#example)

If you're not using transitions you rarely need to the above techniques. However if you're using transitions and want to control how elements enter and exit the page, the above techniques are required. See the [transitions](https://www.d3indepth.com/transitions) chapter for examples using transitions.

For now here's an example that sets the opacity of entering nodes to 0.25:

```js
function getData() {
  let data = [];
  let numItems = Math.ceil(Math.random() * 5);

  for(let i=0; i<numItems; i++) {
    data.push(40);
  }

  return data;
}

function update(data) {
  select('.chart')
    .selectAll('circle')
    .data(data)
    .join(
      function(enter) {
        return enter.append('circle')
          .style('opacity', 0.25);
      },
      function(update) {
        return update.style('opacity', 1);
      }
    )
    .attr('cx', function(d, i) {
      return i * 100;
    })
    .attr('cy', 50)
    .attr('r', function(d) {
      return 0.5 * d;
    })
    .style('fill', 'orange');
}

function updateAll() {
	let myData = getData();
	update(myData);
}

updateAll();

select("button")
	.on("click", updateAll);
```

Update

The enter function appends a `circle` to each element in the enter selection and sets their opacity to 0.25. The update function sets the opacity of existing circles to 1. The `.attr` and `.style` methods after the `.join` method apply to entering and existing elements.

Now circles that have just entered the page are feint, while those that were already in existence are solid.

The above example is not very representative of how you'd use enter, exit and update functions in practice. See the [transitions](https://www.d3indepth.com/transitions) page for representative examples.

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## Visualizing Hierarchical Data
# D3 Hierarchies

_How to visualise hierarchical data (data in the shape of trees) using D3.js. This article shows how to create a nested (or hierarchical) data structure from an array of data. It also covers visualising hierarchies using D3, including treemaps, circle packing and sunburst charts._

A common technique when analysing or visualising data is to organise your data into **groups**.

For example, here's some film data:

| Title | Distributor | Genre | Worldwide\_Gross | Rotten\_Tomatoes\_Rating |
| --- | --- | --- | --- | --- |
| Adaptation | Sony Pictures | Comedy | 22498520 | 91 |
| Air Bud | Walt Disney Pictures | Comedy | 27555061 | 45 |
| Air Force One | Sony Pictures | Action | 315268353 | 78 |
| Alex & Emma | Warner Bros. | Drama | 15358583 | 11 |
| Alexander | Warner Bros. | Adventure | 167297191 | 16 |
| Ali | Sony Pictures | Drama | 84383966 | 67 |
| Alice in Wonderland | Walt Disney Pictures | Adventure | 1023291110 | 51 |
| Alive | Walt Disney Pictures | Adventure | 36299670 | 71 |
| All the King's Men | Sony Pictures | Drama | 9521458 | 11 |
| Amadeus | Warner Bros. | Drama | 51973029 | 96 |

Let's group it according to **Distributor** and count the number of films in each group:

| Distributor | Count |
| --- | --- |
| Sony Pictures | 4 |
| Walt Disney Pictures | 3 |
| Warner Bros. | 3 |

You can also group by more than one category. For example let's group by **Distributor**, then group by **Genre**:

| Distributor | Genre | Count |
| --- | --- | --- |
| Sony Pictures | Action | 1 |
| Comedy | 1 |
| Drama | 2 |
| Walt Disney Pictures | Adventure | 2 |
| Comedy | 1 |
| Warner Bros. | Adventure | 1 |
| Drama | 2 |

> In the world of spreadsheets, the above table is also known as a pivot table. If you're familiar with databases you can achieve similar affects using the SQL statement `GROUP BY`.

The data how has a hierarchical structure. At the top level are **Distributors** (Sony Pictures, Walt Disney Pictures etc.) and at the next level are **Genres** (Action, Adventure, Comedy etc.).

You can think of a hiearchical structure as a tree-like struture where a root item (or 'node') splits into top level groups (Distributors in our example). Each top level group splits into second level groups (Genres in our example), and so on:

Sony PicturesWalt Disney PicturesWarner Bros.ComedyActionDramaComedyAdventureDramaAdventure1121221

The topmost item (or **node**) is known as the **root node**. The bottommost items are known as **leaves** or **leaf nodes**. In the leaf nodes of the above example, the count is displayed under the dot.

You can also aggregate (or 'rollup') the groups in different ways. For example you can sum `Worldwide_Gross`:

| Distributor | Genre | Sum of Worldwide\_Gross |
| --- | --- | --- |
| Sony Pictures | Action | 315268353 |
| Comedy | 22498520 |
| Drama | 93905424 |
| Walt Disney Pictures | Adventure | 1059590780 |
| Comedy | 27555061 |
| Warner Bros. | Adventure | 167297191 |
| Drama | 67331612 |

There are several ways in which hierarchical data can be visualised including **trees**, **treemaps**, **packed circles** and **sunbursts**. Each of these can be created using D3 and we'll cover each of them later in this chapter.

First we'll look at how D3 can help us create a hierarchical data structure from flat data.

## Creating a hierarchy from an array of data [Anchor link for: creating a hierarchy from an array of data](https://www.d3indepth.com/hierarchies/\#creating-a-hierarchy-from-an-array-of-data)

Given an array of data such as:

```js
let data = [\
  {\
    "Title": "Adaptation",\
    "Distributor": "Sony Pictures",\
    "Genre": "Comedy",\
    "Worldwide_Gross": 22498520,\
    "Rating": 91\
  },\
  {\
    "Title": "Air Bud",\
    "Distributor": "Walt Disney Pictures",\
    "Genre": "Comedy",\
    "Worldwide_Gross": 27555061,\
    "Rating": 45\
  },\
  {\
    "Title": "Air Force One",\
    "Distributor": "Sony Pictures",\
    "Genre": "Action",\
    "Worldwide_Gross": 315268353,\
    "Rating": 78\
  },\
  ...\
];
```

you can use D3's `rollup` function to group the data by any of the categorical properties. `rollup` is imported from the `d3-array` module.

The first argument of `rollup` is the array you want to group.

The next argument is a **reduce** function. This is a function that takes an array of values and outputs a single value. For example it might iterate through the array, summing one of the properties (such as `Worldwide_Gross`).

The remaining argument(s) are functions which specify which properties to group by.

Let's group by `Distributor` and `Genre` and sum `Worldwide_Gross` across the items in each group:

```js
function sumWorldwideGross(group) {
  return sum(group, function(d) {
    return d.Worldwide_Gross;
  });
}

let groups = rollup(data,
                       sumWorldwideGross,
                       function(d) { return d.Distributor; },
                       function(d) { return d.Genre; }
                      );
```

In the above example `rollup` groups `data` by `Distributor` and `Genre`. Each of the groups is then passed into `sumWorldwideGross` which returns the sum of `Worldwide_Gross`.

`rollup` returns a nested map object. (Maps, just like regular JavaScript objects, hold key-value pairs. You can read more about them [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).)

You can inspect the map returned by `rollup` using `.get`:

```js
// Get Sony Pictures
groups.get('Sony Pictures');  // {"Comedy" => 22498520, "Action" => 315268353, "Drama" => 93905424}

// Get Drama within Sony Pictures
groups.get('Sony Pictures').get('Drama');  // 93905424
```

\\n\\n

\\n

\\n\\n \\n","css":"\\nbody {\\n font-family: \\"Helvetica Neue\\", Helvetica, sans-serif;\\n font-size: 14px;\\n color: #333;\\n}\\n","js":"// For bundlers such as Vite and Webpack omit https://esm.sh/\\nimport { rollup, sum } from 'https://esm.sh/d3-array';\\n\\nlet data = \[\\n\\t{\\"Title\\": \\"Adaptation\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 22498520, \\"Rating\\": 91},\\n\\t{\\"Title\\": \\"Air Bud\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 27555061, \\"Rating\\": 45},\\n\\t{\\"Title\\": \\"Air Force One\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Action\\", \\"Worldwide\_Gross\\": 315268353, \\"Rating\\": 78},\\n\\t{\\"Title\\": \\"Alex & Emma\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 15358583, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Alexander\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 167297191, \\"Rating\\": 16},\\n\\t{\\"Title\\": \\"Ali\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 84383966, \\"Rating\\": 67},\\n\\t{\\"Title\\": \\"Alice in Wonderland\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 1023291110, \\"Rating\\": 51},\\n\\t{\\"Title\\": \\"Alive\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 36299670, \\"Rating\\": 71},\\n\\t{\\"Title\\": \\"All the King's Men\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 9521458, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Amadeus\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 51973029, \\"Rating\\": 96}\\n\];\\n\\nfunction sumWorldwideGross(group) {\\n\\treturn sum(group, function(d) {\\n\\t\\treturn d.Worldwide\_Gross;\\n\\t});\\n}\\n\\nfunction doRollup(data) {\\n\\tlet groups = rollup(data, sumWorldwideGross,\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Distributor; },\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Genre; }\\n\\t\\t\\t\\t\\t\\t );\\n\\n\\t// Get Sony Pictures\\n\\tconsole.log(groups.get('Sony Pictures'));\\n\\n\\t// Get Drama within Sony Pictures\\n\\tconsole.log(groups.get('Sony Pictures').get('Drama'));\\n}\\n\\n\\ndoRollup(data);\\n"}'>

-->

The first `.get` returns the group associated with `Sony Pictures`. This group contains 3 items: `Comedy`, `Action` and `Drama`. (You can compare this with the table we showed previously.)

The second `.get` returns the value associated with `Drama` within the `Sony Pictures` group (93905424). This returns the value computed by the rollup function ( `sumWorldwideGross`) because we're at the lowest level of the hieararchy.

## hierarchy structure [Anchor link for: hierarchy structure](https://www.d3indepth.com/hierarchies/\#hierarchy-structure)

D3 has a bespoke hierarchy data structure that gives you some useful features over and above the map object seen previously.

It's created by calling `hierarchy` (imported from `d3-hierarchy`) and passing in the map object generated by `rollup`:

```js
function sumWorldwideGross(group) {
  return sum(group, function(d) {
    return d.Worldwide_Gross;
  });
}

let groups = rollup(data,
                       sumWorldwideGross,
                       function(d) { return d.Distributor; },
                       function(d) { return d.Genre; }
                      );

let root = hierarchy(groups);
```

\\n\\n

\\n

\\n\\n \\n","css":"\\nbody {\\n font-family: \\"Helvetica Neue\\", Helvetica, sans-serif;\\n font-size: 14px;\\n color: #333;\\n}\\n","js":"// For bundlers such as Vite and Webpack omit https://esm.sh/\\nimport { rollup, sum } from 'https://esm.sh/d3-array';\\nimport { hierarchy } from 'https://esm.sh/d3-hierarchy';\\n\\nlet data = \[\\n\\t{\\"Title\\": \\"Adaptation\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 22498520, \\"Rating\\": 91},\\n\\t{\\"Title\\": \\"Air Bud\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 27555061, \\"Rating\\": 45},\\n\\t{\\"Title\\": \\"Air Force One\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Action\\", \\"Worldwide\_Gross\\": 315268353, \\"Rating\\": 78},\\n\\t{\\"Title\\": \\"Alex & Emma\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 15358583, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Alexander\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 167297191, \\"Rating\\": 16},\\n\\t{\\"Title\\": \\"Ali\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 84383966, \\"Rating\\": 67},\\n\\t{\\"Title\\": \\"Alice in Wonderland\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 1023291110, \\"Rating\\": 51},\\n\\t{\\"Title\\": \\"Alive\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 36299670, \\"Rating\\": 71},\\n\\t{\\"Title\\": \\"All the King's Men\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 9521458, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Amadeus\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 51973029, \\"Rating\\": 96}\\n\];\\n\\nfunction sumWorldwideGross(group) {\\n\\treturn sum(group, function(d) {\\n\\t\\treturn d.Worldwide\_Gross;\\n\\t});\\n}\\n\\nfunction doRollup(data) {\\n\\tlet groups = rollup(data, sumWorldwideGross,\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Distributor; },\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Genre; }\\n\\t\\t\\t\\t\\t\\t );\\n\\n\\tlet root = hierarchy(groups);\\n\\n\\tconsole.log(root);\\n}\\n\\n\\ndoRollup(data);\\n"}'>

-->

> You can also pass a nested object into `hierarchy`. The layout examples later on use this approach.

The output of `hierarchy` is a nested object that looks something like:

```json
{
  data: [undefined, Map(3)],
  children: [\
    {\
      data: ["Sony Pictures", Map(3)],\
      children: [...],\
      depth: 1,\
      height: 1,\
      parent: {...} // this item's parent node\
    }.\
    {\
      data: ["Walt Disney Pictures", Map(2)],\
      children: [...],\
      depth: 1,\
      height: 1,\
      parent: {...} // this item's parent node\
    }.\
    {\
      data: ["Warner Bros.", Map(3)],\
      children: [...],\
      depth: 1,\
      height: 1,\
      parent: {...} // this item's parent node\
    }\
  ],
  depth: 0,
  height: 2,
  parent: null
}
```

It's similar in structure to the map object that's passed into `hierarchy`. The difference is that it's a regular JavaScript object and has various properties and methods defined on it that provides additional functionality.

Each item (or **node**) in the hierarchy has properties: `data`, `children`, `depth`, `height` and `parent`.

`data` is the associated item from the map or object that's passed into `hierarchy`. In this example it's a two-element array containing the group name and the group's value. For leaf nodes (the nodes at the bottom-most level), the value is the aggregated value (for example, the sum of `Worldwide_Gross`). Otherwise, it's the map representing the items in the group. Typically you won't need to access the value because the hierarchy makes this data available through its `children` and `value` properties.

`children` is an array containing the node's children. `depth` and `height` indicate the depth and height of the node within the hierarchy. (The root node has a depth of zero and leaf nodes have a height of zero.)

`parent` references the node's parent node.

The leaf nodes look something like:

```json
{
  data: ["Comedy", 22498520],
  depth: 2,
  height: 0,
  parent: {...} // this item's parent node
}
```

You can see that the `data` property contains the rolled up value. If the rolled up value is a sum or count, it can be be propagated back up the tree using the hierarchy's `.sum` method:

```js
function sumWorldwideGross(group) {
  return sum(group, function(d) {
    return d.Worldwide_Gross;
  });
}

let groups = rollup(data,
                       sumWorldwideGross,
                       function(d) { return d.Distributor; },
                       function(d) { return d.Genre; }
                      );

let root = hierarchy(groups);
root.sum(function(d) {
  return d[1];
});
```

\\n\\n

\\n

\\n\\n \\n","css":"\\nbody {\\n font-family: \\"Helvetica Neue\\", Helvetica, sans-serif;\\n font-size: 14px;\\n color: #333;\\n}\\n","js":"// For bundlers such as Vite and Webpack omit https://esm.sh/\\nimport { rollup, sum } from 'https://esm.sh/d3-array';\\nimport { hierarchy } from 'https://esm.sh/d3-hierarchy';\\n\\nlet data = \[\\n\\t{\\"Title\\": \\"Adaptation\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 22498520, \\"Rating\\": 91},\\n\\t{\\"Title\\": \\"Air Bud\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Comedy\\", \\"Worldwide\_Gross\\": 27555061, \\"Rating\\": 45},\\n\\t{\\"Title\\": \\"Air Force One\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Action\\", \\"Worldwide\_Gross\\": 315268353, \\"Rating\\": 78},\\n\\t{\\"Title\\": \\"Alex & Emma\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 15358583, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Alexander\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 167297191, \\"Rating\\": 16},\\n\\t{\\"Title\\": \\"Ali\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 84383966, \\"Rating\\": 67},\\n\\t{\\"Title\\": \\"Alice in Wonderland\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 1023291110, \\"Rating\\": 51},\\n\\t{\\"Title\\": \\"Alive\\", \\"Distributor\\": \\"Walt Disney Pictures\\", \\"Genre\\": \\"Adventure\\", \\"Worldwide\_Gross\\": 36299670, \\"Rating\\": 71},\\n\\t{\\"Title\\": \\"All the King's Men\\", \\"Distributor\\": \\"Sony Pictures\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 9521458, \\"Rating\\": 11},\\n\\t{\\"Title\\": \\"Amadeus\\", \\"Distributor\\": \\"Warner Bros.\\", \\"Genre\\": \\"Drama\\", \\"Worldwide\_Gross\\": 51973029, \\"Rating\\": 96}\\n\];\\n\\nfunction sumWorldwideGross(group) {\\n\\treturn sum(group, function(d) {\\n\\t\\treturn d.Worldwide\_Gross;\\n\\t});\\n}\\n\\nfunction doRollup(data) {\\n\\tlet groups = rollup(data, sumWorldwideGross,\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Distributor; },\\n\\t\\t\\t\\t\\t\\t function(d) { return d.Genre; }\\n\\t\\t\\t\\t\\t\\t );\\n\\n\\tlet root = hierarchy(groups);\\n\\troot.sum(function(d) {\\n\\t\\treturn d\[1\];\\n\\t});\\n\\n\\tconsole.log(root);\\n}\\n\\n\\ndoRollup(data);\\n"}'>

-->

The `.sum` method takes an accessor function whose first parameter is the node's `data` property. The accessor function returns the value to sum by.

> If you're passing the output of `rollup` into `hierarchy`, the accessor function will usually return `d[1]` which is the rolled up value generated by `rollup`.

Each leaf node will now have a `value` property equivalent to its rolled up value. For example:

```json
{
  data: ["Comedy", 22498520],
  depth: 2,
  height: 0,
  parent: {...}, // this item's parent node
  value: 22498520
}
```

The non-leaf nodes will also have a `value` property which is the sum of the values of its children.

```json
{
  data: ["Sony Pictures", Map(3)],
  depth: 1,
  height: 1,
  parent: {...}, // this item's parent node
  value: 431672297
}
```

> The `.value` property generated by the `.sum` method is used by some of the layouts we'll cover later such as treemap and packed circles.

Each node in a D3 hierarchy has handy methods such as `.descendants`, `.ancestors` and `.links`.

`.descendants` returns an array containing the node and its descendants. `.ancestors` returns an array containing the node and its ancestors (all the way to the root).

`.links` returns an array of objects representing the connections between the node and its children, all the way to the leaves. We'll see this in use later on.

## Visualising hierarchies [Anchor link for: visualising hierarchies](https://www.d3indepth.com/hierarchies/\#visualising-hierarchies)

There are several ways in which hierarchies can be visualised including trees:

treemaps:

A1B1B2C1C2C3

packed circles:

B2C1C2C3

and sunburst charts:

> You can also use stacked bar charts for visualising hierarchies!

D3 supports the above visualisations using **layout functions**. These take a `hierarchy` structure and add **visual variables such as position and size** to it.

For example the tree layout adds `x` and `y` values to each node such that the nodes form a tree-like shape.

In this page we look at the `tree`, `cluster`, `treemap`, `pack` and `partition` layouts, all of which are imported from the `d3-hierarchy` module.

Note that `treemap`, `pack` and `partition` are designed to lay out hierarchies where the nodes have an associated numeric value (e.g. revenue, population etc.).

### Tree layout [Anchor link for: tree layout](https://www.d3indepth.com/hierarchies/\#tree-layout)

The `tree` layout arranges the nodes of a hierarchy in a **tree like arrangement**.

Start by creating a tree layout function using `tree()`:

```js
let treeLayout = tree();
```

> tree() returns a layout function into which you can pass a hierarchy object.

You can configure the tree's size using `.size`:

```js
treeLayout.size([400, 200]);
```

You can then call `treeLayout`, passing in the hierarchy object `root` that was defined above:

```js
treeLayout(root);
```

This'll write `x` and `y` values on each node of `root`.

To draw the nodes:

- use `root.descendants()` to get an array of all the nodes
- join this array to circles (or any other type of SVG element)
- use `x` and `y` to position the circles

To draw the links:

- use `root.links()` to get an array of all the links
- join the array to line (or path) elements
- use `x` and `y` of the link's `source` and `target` properties to position the line

> `root.links()` returns an array where each element is an object containing two properties `source` and `target` which represent the link's source and target nodes.

```js
// Nodes
select('svg g.nodes')
  .selectAll('circle.node')
  .data(root.descendants())
  .join('circle')
  .classed('node', true)
  .attr('cx', function(d) {return d.x;})
  .attr('cy', function(d) {return d.y;})
  .attr('r', 4);

// Links
select('svg g.links')
  .selectAll('line.link')
  .data(root.links())
  .join('line')
  .classed('link', true)
  .attr('x1', function(d) {return d.source.x;})
  .attr('y1', function(d) {return d.source.y;})
  .attr('x2', function(d) {return d.target.x;})
  .attr('y2', function(d) {return d.target.y;});
```

> For simplicity, in this and the following CodePen examples, a hierarchy object is created from a nested object (rather than from an array).

### Cluster layout [Anchor link for: cluster layout](https://www.d3indepth.com/hierarchies/\#cluster-layout)

The `cluster` layout is very similar to the `tree` layout the main difference being **all leaf nodes are placed at the same depth**.

```js
let clusterLayout = cluster()
  .size([400, 200]);

let root = hierarchy(data);

clusterLayout(root);
```

### Treemap layout [Anchor link for: treemap layout](https://www.d3indepth.com/hierarchies/\#treemap-layout)

Treemaps were invented by [Ben Shneiderman](https://en.wikipedia.org/wiki/Ben_Shneiderman) to visually represent hierarchies where **each item has an associated value**.

For example, imagine you have country population data where each country has a region and a population value.

You can use a treemap to represent each region as a rectangle. Each region consists of smaller rectangles which represent a country. Each country is sized proportionally to the population:

![](https://www.d3indepth.com/img/layouts/treemap.png)

Create a treemap layout function by calling `treemap()` :

```js
let treemapLayout = treemap();
```

As before you can configure the layout:

```js
treemapLayout
  .size([400, 200])
  .paddingOuter(10);
```

Before applying this layout to your hierarchy **you must run `.sum()` on the hierarchy**. This traverses the tree and sets `.value` on each node to be the sum of its children:

```js
root.sum(function(d) {
  return d.value;
});
```

> Note an accessor function has been passed into `.sum()` to specify which property to sum.

You can now call `treemapLayout`, passing in the hierarchy object `root` that was defined earlier:

```js
treemapLayout(root);
```

The treemap layout function adds 4 properties `x0`, `x1`, `y0` and `y1` to each node which specify the dimensions of each rectangle in the treemap.

Now you can join the nodes to `rect` elements and update the `x`, `y`, `width` and `height` properties of each `rect`:

```js
select('svg g')
  .selectAll('rect')
  .data(root.descendants())
  .join('rect')
  .attr('x', function(d) { return d.x0; })
  .attr('y', function(d) { return d.y0; })
  .attr('width', function(d) { return d.x1 - d.x0; })
  .attr('height', function(d) { return d.y1 - d.y0; })
```

If you'd like labels in each rectangle you can join `g` elements to the array and add `rect` and `text` elements to each `g`:

```js
let nodes = select('svg g')
  .selectAll('g')
  .data(rootNode.descendants())
  .join('g')
  .attr('transform', function(d) {return 'translate(' + [d.x0, d.y0] + ')'})

nodes
  .append('rect')
  .attr('width', function(d) { return d.x1 - d.x0; })
  .attr('height', function(d) { return d.y1 - d.y0; })

nodes
  .append('text')
  .attr('dx', 4)
  .attr('dy', 14)
  .text(function(d) {
    return d.data.name;
  })
```

A1B1B2C1C2C3

`treemap` layouts can be configured in a number of ways:

- the padding around a node's children can be set using `.paddingOuter`
- the padding between sibling nodes can be set using `.paddingInner`
- outer and inner padding can be set at the same time using `.padding`
- the outer padding can also be fine tuned using `.paddingTop`, `.paddingBottom`, `.paddingLeft` and `.paddingRight`.

A1B1B2C1C2C3

In the above example `paddingTop` is 20 and `paddingInner` is 2.

Treemaps have more than one strategy for arranging the rectangles. D3 has a few built-in ones such as `treemapBinary`, `treemapDice`, `treemapSlice`, `treemapSliceDice` and `treemapSquarify`.

`treemapBinary` strives for a balance between horizontal and vertical partitions, `treemapDice` partitions horizontally, `treemapSlice` partitions vertically, `treemapSliceDice` alternates between horizontal and vertical partioning and `treemapSquarify` allows the aspect ratio of the rectangles to be influenced.

You can select a tiling strategy using the `.tile` method:

```js
treemapLayout.tile(treemapDice)
```

treemapBinary11.11.21.1.11.1.21.1.31.1.3.11.1.3.21.1.3.3treemapDice11.11.21.1.11.1.21.1.31.1.3.11.1.3.21.1.3.3treemapSlice11.11.21.1.11.1.21.1.31.1.3.11.1.3.21.1.3.3treemapSliceDice11.11.21.1.11.1.21.1.31.1.3.11.1.3.21.1.3.3treemapSquarify11.11.21.1.11.1.21.1.31.1.3.11.1.3.21.1.3.3

The effect of different squarify ratios can be seen [here](https://www.d3indepth.com/examples-merged/layouts/treemap-squarify-ratios).

### Pack layout [Anchor link for: pack layout](https://www.d3indepth.com/hierarchies/\#pack-layout)

The pack layout is similar to the tree layout but **circles** are used to represent nodes.

In this example each country is represented by a circle (sized according to population) and the countries are grouped by region.

![](https://www.d3indepth.com/img/layouts/pack.png)

Create a pack layout function using `pack()`:

```js
let packLayout = pack();
```

As before you can configure its size by passing an array `[width, height]` into the `.size` method:

```js
packLayout.size([300, 300]);
```

As with the `treemap` you must **call `.sum()` on the hierarchy object `root`** before applying the `pack` layout:

```js
rootNode.sum(function(d) {
  return d.value;
});

packLayout(rootNode);
```

The `pack` layout adds `x`, `y` and `r` (for radius) properties to each node.

Now you can join `circle` elements to each descendant of `root`:

```js
select('svg g')
  .selectAll('circle')
  .data(rootNode.descendants())
  .join('circle')
  .attr('cx', function(d) { return d.x; })
  .attr('cy', function(d) { return d.y; })
  .attr('r', function(d) { return d.r; })
```

Labels can be added by creating `g` elements for each descendant:

```js
let nodes = select('svg g')
  .selectAll('g')
  .data(rootNode.descendants())
  .join('g')
  .attr('transform', function(d) {return 'translate(' + [d.x, d.y] + ')'})

nodes
  .append('circle')
  .attr('r', function(d) { return d.r; })

nodes
  .append('text')
  .attr('dy', 4)
  .text(function(d) {
    return d.children === undefined ? d.data.name : '';
  })
```

B2C1C2C3

The padding around each circle can be configured using `.padding()`:

```js
packLayout.padding(10)
```

### Partition layout [Anchor link for: partition layout](https://www.d3indepth.com/hierarchies/\#partition-layout)

The `partition` layout subdivides a rectangular space into layers, each of which represents a layer in the hierarchy. Each layer is further subdivided for each node in the layer:

![](https://www.d3indepth.com/img/layouts/partition.png)

Create a partition layout function using `partition()`:

```js
let partitionLayout = partition();
```

As before you can configure its size by passing an array `[width, height]` into the `.size` method:

```js
partitionLayout.size([400, 200]);
```

As with the `treemap` you must call `.sum()` on the hierarchy object `root` and before applying the `partition` layout:

```js
rootNode.sum(function(d) {
  return d.value;
});

partitionLayout(rootNode);
```

The `partition` layout adds `x0`, `x1`, `y0` and `y1` properties to each node.

You can now join `rect` elements to each descendant of `root`:

```js
select('svg g')
  .selectAll('rect')
  .data(rootNode.descendants())
  .join('rect')
  .attr('x', function(d) { return d.x0; })
  .attr('y', function(d) { return d.y0; })
  .attr('width', function(d) { return d.x1 - d.x0; })
  .attr('height', function(d) { return d.y1 - d.y0; });
```

Padding can be added between nodes using `.padding()`:

```js
partitionLayout.padding(2);
```

If you'd like to change the orientation of the partition layout so that the layers run left to right you can swap `x0` with `y0` and `x1` with `y1` when defining the `rect` elements:

```js
  .attr('x', function(d) { return d.y0; })
  .attr('y', function(d) { return d.x0; })
  .attr('width', function(d) { return d.y1 - d.y0; })
  .attr('height', function(d) { return d.x1 - d.x0; });
```

You can also map the `x` dimension into a rotation angle and `y` into a radius to create a sunburst partition:

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Scale Functions Guide
# D3 Scale functions

_How to use D3 scale functions to transform data values into visual values such as positions and colours. After explaning scale basics we cover linear, square root, log, sequential, quantized, quantile, threshold, ordinal, band and point scales._

Scale functions are JavaScript functions that:

- take an input (usually a number, date or category) and
- return a value (such as a coordinate, a colour, a length or a radius)

They're typically used to transform (or 'map') data values into visual variables (such as position, length and colour).

For example, suppose you have some data:

```js
[ 0, 2, 3, 5, 7.5, 9, 10 ]
```

you can create a scale function using:

```js
import { scaleLinear } from 'd3-scale';

let myScale = scaleLinear()
  .domain([0, 10])
  .range([0, 600]);
```

D3 creates a function `myScale` which accepts input between 0 and 10 (the **domain**) and maps it to output between 0 and 600 (the **range**).

You can use `myScale` to calculate positions based on the data:

```js
myScale(0);   // returns 0
myScale(2);   // returns 120
myScale(3);   // returns 180
...
myScale(10);  // returns 600
```

02357.5910

Scales are mainly used for transforming data values to visual variables such as position, length and colour.

For example they can transform:

- data values into lengths between 0 and 500 for a bar chart
- data values into positions between 0 and 200 for line charts
- % change data (+4%, +10%, -5% etc.) into a continuous range of colours (with red for negative and green for positive)
- dates into positions along an x-axis.

### Constructing scales [Anchor link for: constructing scales](https://www.d3indepth.com/scales/\#constructing-scales)

D3's scale functions are provided by the `d3-selection` module. For example:

```js
import { scaleLinear } from 'd3-scale';
```

To create a linear scale use:

```js
let myScale = scaleLinear();
```

As it stands the above function isn't very useful so you can configure the input bounds (the **domain**) as well as the output bounds (the **range**):

```js
myScale
  .domain([0, 100])
  .range([0, 800]);
```

This results in a scale function that accepts input between 0 and 100 and linearly maps it to between 0 and 800:

```js
myScale(0);    // returns 0
myScale(50);   // returns 400
myScale(100);  // returns 800
```

You can experiment with scale functions by visiting [jsconsole](https://jsconsole.com/) and loading D3 using:

```js
:load https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.4/d3.min.js
```

You can then use D3's scale functions by preceding them with `d3.` ( `d3` followed by a dot).

For example:

```js
let myScale = d3.scaleLinear()
myScale.range([0, 100])
myScale(0.5)
```

### D3 scale types [Anchor link for: d3 scale types](https://www.d3indepth.com/scales/\#d3-scale-types)

D3 has around 12 different scale types (scaleLinear, scalePow, scaleQuantise, scaleOrdinal etc.) and broadly speaking they can be classified into 3 groups:

- [scales with continuous input and continuous output](https://www.d3indepth.com/scales/#scales-with-continuous-input-and-continuous-output)
- [scales with continuous input and discrete output](https://www.d3indepth.com/scales/#scales-with-continuous-input-and-discrete-output)
- [scales with discrete input and discrete output](https://www.d3indepth.com/scales/#scales-with-discrete-input-and-discrete-output)

> Continuous data is typically numeric data but also includes time and dates. Discrete data has a set number of values (such as the twelve months of the year).)

We'll now look at each of these three categories.

### Scales with continuous input and continuous output [Anchor link for: scales with continuous input and continuous output](https://www.d3indepth.com/scales/\#scales-with-continuous-input-and-continuous-output)

In this chapter we cover scale functions that map from a **continuous input domain** to a **continuous output range**.

#### scaleLinear [Anchor link for: scalelinear](https://www.d3indepth.com/scales/\#scalelinear)

Linear scales are probably the most commonly used scale type as they are the most suitable scale for transforming data values into positions and lengths.

They use a linear function y=mx+c to interpolate across the domain and range. (Imagine a graph where the domain is on the x-axis and the range is on the y-axis. If you plot a linear function it'll be a straight line.)

```js
let linearScale = scaleLinear()
  .domain([0, 10])
  .range([0, 600]);

linearScale(0);   // returns 0
linearScale(5);   // returns 300
linearScale(10);  // returns 600
```

Linear scale functions are typically used to transform data values into positions and lengths. They are useful when creating bar charts, line charts and many other chart types.

The output range can also be specified as colours:

```js
let linearScale = scaleLinear()
  .domain([0, 10])
  .range(['yellow', 'red']);

linearScale(0);   // returns "rgb(255, 255, 0)"
linearScale(5);   // returns "rgb(255, 128, 0)"
linearScale(10);  // returns "rgb(255, 0, 0)"
```

This can be useful for visualisations such as choropleth maps, but also consider `scaleQuantize`, `scaleQuantile` and `scaleThreshold`.

#### scaleSqrt [Anchor link for: scalesqrt](https://www.d3indepth.com/scales/\#scalesqrt)

The `scaleSqrt` scale is useful for sizing circles by area (rather than radius). (When using circle size to represent data, it's considered better practice to [set the area, rather than the radius](https://eagereyes.org/blog/2008/linear-vs-quadratic-change) proportionally to the data.)

```js
let sqrtScale = scaleSqrt()
  .domain([0, 100])
  .range([0, 30]);

sqrtScale(0);   // returns 0
sqrtScale(50);  // returns 21.21...
sqrtScale(100); // returns 30
```

#### scalePow [Anchor link for: scalepow](https://www.d3indepth.com/scales/\#scalepow)

`scalePow` is a more general version of `scaleSqrt`. This scale interpolates using a power function y=mxk+c. The exponent `k` is set using `.exponent()`:

```js
let powerScale = scalePow()
  .exponent(0.5)
  .domain([0, 100])
  .range([0, 30]);

powerScale(0);   // returns 0
powerScale(50);  // returns 21.21...
powerScale(100); // returns 30
```

(I've never used this scale, by the way!)

#### scaleLog [Anchor link for: scalelog](https://www.d3indepth.com/scales/\#scalelog)

`scaleLog` interpolates using a log function y=m\*log(x)+b and can be useful when the data has an exponential nature to it.

```js
let logScale = scaleLog()
  .domain([10, 100000])
  .range([0, 600]);

logScale(10);     // returns 0
logScale(100);    // returns 150
logScale(1000);   // returns 300
logScale(100000); // returns 600
```

10100100010000100000

#### scaleTime [Anchor link for: scaletime](https://www.d3indepth.com/scales/\#scaletime)

`scaleTime` is similar to `scaleLinear` except the domain is expressed as an array of dates. (It's **very** useful when dealing with time series data.)

```js
timeScale = scaleTime()
  .domain([new Date(2016, 0, 1), new Date(2017, 0, 1)])
  .range([0, 700]);

timeScale(new Date(2016, 0, 1));   // returns 0
timeScale(new Date(2016, 6, 1));   // returns 348.00...
timeScale(new Date(2017, 0, 1));   // returns 700
```

Fri Jan 01 2016Fri Apr 01 2016Fri Jul 01 2016Sun Jan 01 2017

#### scaleSequential [Anchor link for: scalesequential](https://www.d3indepth.com/scales/\#scalesequential)

`scaleSequential` is used for mapping continuous values to an output range determined by a preset (or custom) **interpolator**. (An interpolator is a function that accepts input between 0 and 1 and outputs an interpolated value between two numbers, colours, strings etc.)

The `d3-scale-chromatic` module provides a number of preset interpolators including many colour ones. For example you can use `interpolateRainbow` to create the well known rainbow colour scale:

```js
let sequentialScale = scaleSequential()
  .domain([0, 100])
  .interpolator(interpolateRainbow);

sequentialScale(0);   // returns 'rgb(110, 64, 170)'
sequentialScale(50);  // returns 'rgb(175, 240, 91)'
sequentialScale(100); // returns 'rgb(110, 64, 170)'
```

Note that the interpolator determines the output range so you don't need to specify the range yourself.

The example below shows some of the other colour interpolators provided by D3:

interpolateViridisinterpolateInfernointerpolateMagmainterpolatePlasmainterpolateWarminterpolateCoolinterpolateRainbowinterpolateCubehelixDefault

#### Clamping [Anchor link for: clamping](https://www.d3indepth.com/scales/\#clamping)

By default `scaleLinear`, `scalePow`, `scaleSqrt`, `scaleLog`, `scaleTime` and `scaleSequential` extrapolate when the input value goes beyond the domain.

For example:

```js
let linearScale = scaleLinear()
  .domain([0, 10])
  .range([0, 100]);

linearScale(20);  // returns 200
linearScale(-10); // returns -100
```

You can **clamp** the scale function so that the input value stays within the domain using `.clamp`:

```js
linearScale.clamp(true);

linearScale(20);  // returns 100
linearScale(-10); // returns 0
```

You can switch off clamping using `.clamp(false)`.

#### Nice [Anchor link for: nice](https://www.d3indepth.com/scales/\#nice)

If the domain has been computed automatically from real data (e.g. by using `extent`) the start and end values might not be round figures. This isn't necessarily a problem, but if using the scale to define an axis, it can look a bit untidy:

```js
let data = [0.243, 0.584, 0.987, 0.153, 0.433];
let extent = extent(data);

let linearScale = scaleLinear()
  .domain(extent)
  .range([0, 100]);
```

0.20.30.40.50.60.70.80.9

Therefore D3 provides a function `.nice()` on the scales in this chapter which will round the domain to 'nice' round values:

```js
let data = [0.243, 0.584, 0.987, 0.153, 0.433];
let extent = extent(data);

let linearScale = scaleLinear()
  .domain(extent)
  .range([0, 100])
  .nice();
```

0.10.20.30.40.50.60.70.80.91.0

Note that `.nice()` must be called each time the domain is updated.

#### Multiple segments [Anchor link for: multiple segments](https://www.d3indepth.com/scales/\#multiple-segments)

The domain and range of `scaleLinear`, `scalePow`, `scaleSqrt`, `scaleLog` and `scaleTime` usually consists of two values, but if you provide 3 or more values the scale function is subdivided into multiple segments:

```js
let linearScale = scaleLinear()
  .domain([-10, 0, 10])
  .range(['red', '#ddd', 'blue']);

linearScale(-10);  // returns "rgb(255, 0, 0)"
linearScale(0);    // returns "rgb(221, 221, 221)"
linearScale(5);    // returns "rgb(111, 111, 238)"
```

Typically multiple segments are used for distinguishing between negative and positive values (such as in the example above). You can use as many segments as you like as long as the domain and range are of the same length.

#### Inversion [Anchor link for: inversion](https://www.d3indepth.com/scales/\#inversion)

The `.invert()` method lets you determine a scale function's **input** value given an **output** value (provided the scale function has a numeric domain):

```js
let linearScale = scaleLinear()
  .domain([0, 10])
  .range([0, 100]);

linearScale.invert(50);   // returns 5
linearScale.invert(100);  // returns 10
```

A common use case is when you want to convert a user's click along an axis into a domain value:

−50−40−30−20−1001020304050

Click on the grey band

### Scales with continuous input and discrete output [Anchor link for: scales with continuous input and discrete output](https://www.d3indepth.com/scales/\#scales-with-continuous-input-and-discrete-output)

#### scaleQuantize [Anchor link for: scalequantize](https://www.d3indepth.com/scales/\#scalequantize)

`scaleQuantize` accepts continuous input and outputs a number of discrete quantities defined by the range.

```js
let quantizeScale = scaleQuantize()
  .domain([0, 100])
  .range(['lightblue', 'orange', 'lightgreen', 'pink']);

quantizeScale(10);  // returns 'lightblue'
quantizeScale(30);  // returns 'orange'
quantizeScale(90);  // returns 'pink'
```

Each range value is mapped to an equal sized chunk in the domain so in the example above:

- 0 ≤ _u_ < 25 is mapped to 'lightblue'
- 25 ≤ _u_ < 50 is mapped to 'orange'
- 50 ≤ _u_ < 75 is mapped to 'lightgreen'
- 75 ≤ _u_ < 100 is mapped to 'pink'

where _u_ is the input value.

Input values outside the domain are clamped so in our example `quantizeScale(-10)` returns 'lightblue' and `quantizeScale(110)` returns 'pink'.

#### scaleQuantile [Anchor link for: scalequantile](https://www.d3indepth.com/scales/\#scalequantile)

`scaleQuantile` maps continuous numeric input to discrete values. The domain is defined by **an array of numbers**:

```js
let myData = [0, 5, 7, 10, 20, 30, 35, 40, 60, 62, 65, 70, 80, 90, 100];

let quantileScale = scaleQuantile()
  .domain(myData)
  .range(['lightblue', 'orange', 'lightgreen']);

quantileScale(0);   // returns 'lightblue'
quantileScale(20);  // returns 'lightblue'
quantileScale(30);  // returns 'orange'
quantileScale(65);  // returns 'lightgreen'
```

The (sorted) domain array is divided into _n_ equal sized groups where _n_ is the number of range values.

Therefore in the above example the domain array is split into 3 groups where:

- the first 5 values are mapped to 'lightblue'
- the next 5 values to 'orange' and
- the last 5 values to 'lightgreen'.

The split points of the domain can be accessed using `.quantiles()`:

```js
quantileScale.quantiles();  // returns [26.66..., 63]
```

If the range contains 4 values `quantileScale` computes the **quartiles** of the data. In other words, the lowest 25% of the data is mapped to `range[0]`, the next 25% of the data is mapped to `range[1]` etc.

#### scaleThreshold [Anchor link for: scalethreshold](https://www.d3indepth.com/scales/\#scalethreshold)

`scaleThreshold` maps continuous numeric input to discrete values defined by the range. _n-1_ domain split points are specified where _n_ is the number of range values.

In the following example we split the domain at `0`, `50` and `100`

- _u_ < 0 is mapped to '#ccc'
- 0 ≤ _u_ < 50 to 'lightblue'
- 50 ≤ _u_ < 100 to 'orange'
- _u_ ≥ 100 to '#ccc'

where _u_ is the input value.

```js
let thresholdScale = scaleThreshold()
  .domain([0, 50, 100])
  .range(['#ccc', 'lightblue', 'orange', '#ccc']);

thresholdScale(-10);  // returns '#ccc'
thresholdScale(20);   // returns 'lightblue'
thresholdScale(70);   // returns 'orange'
thresholdScale(110);  // returns '#ccc'
```

### Scales with discrete input and discrete output [Anchor link for: scales with discrete input and discrete output](https://www.d3indepth.com/scales/\#scales-with-discrete-input-and-discrete-output)

#### scaleOrdinal [Anchor link for: scaleordinal](https://www.d3indepth.com/scales/\#scaleordinal)

`scaleOrdinal` maps discrete values (specified by an array) to discrete values (also specified by an array). The domain array specifies the possible input values and the range array the output values. The range array will repeat if it's shorter than the domain array.

```js
let myData = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

let ordinalScale = scaleOrdinal()
  .domain(myData)
  .range(['black', '#ccc', '#ccc']);

ordinalScale('Jan');  // returns 'black';
ordinalScale('Feb');  // returns '#ccc';
ordinalScale('Mar');  // returns '#ccc';
ordinalScale('Apr');  // returns 'black';
```

JanFebMarAprMayJunJulAugSepOctNovDec

By default if a value that's not in the domain is used as input, the scale will implicitly add the value to the domain:

```js
ordinalScale('Monday');  // returns 'black';
```

If this isn't the desired behvaiour you can specify an output value for unknown values using `.unknown()`:

```js
ordinalScale.unknown('Not a month');
ordinalScale('Tuesday'); // returns 'Not a month'
```

D3 can also provide preset colour schemes (from [ColorBrewer](http://colorbrewer2.org/#type=sequential&scheme=BuGn&n=3)):

```js
let ordinalScale = scaleOrdinal()
  .domain(myData)
  .range(schemePaired);
```

JanFebMarAprMayJunJulAugSepOctNovDec

#### scaleBand [Anchor link for: scaleband](https://www.d3indepth.com/scales/\#scaleband)

When creating bar charts `scaleBand` helps to determine the geometry of the bars, taking into account padding between each bar. The domain is specified as an array of values (one value for each band) and the range as the minimum and maximum extents of the bands (e.g. the total width of the bar chart).

In effect `scaleBand` will split the range into _n_ bands (where _n_ is the number of values in the domain array) and compute the positions and widths of the bands taking into account any specified padding.

```js
let bandScale = scaleBand()
  .domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
  .range([0, 200]);

bandScale('Mon'); // returns 0
bandScale('Tue'); // returns 40
bandScale('Fri'); // returns 160
```

The width of each band can be accessed using `.bandwidth()`:

```js
bandScale.bandwidth();  // returns 40
```

Two types of padding may be configured:

- `paddingInner` which specifies (as a percentage of the band width) the amount of padding between each band
- `paddingOuter` which specifies (as a percentage of the band width) the amount of padding before the first band and after the last band

Let's add some inner padding to the example above:

```js
bandScale.paddingInner(0.05);

bandScale.bandWidth();  // returns 38.38...
bandScale('Mon');       // returns 0
bandScale('Tue');       // returns 40.40...
```

Putting this all together we can create this bar chart:

#### scalePoint [Anchor link for: scalepoint](https://www.d3indepth.com/scales/\#scalepoint)

`scalePoint` creates scale functions that map from a discrete set of values to equally spaced points along the specified range:

```js
let pointScale = scalePoint()
  .domain(['Mon', 'Tue', 'Wed', 'Thu', 'Fri'])
  .range([0, 500]);

pointScale('Mon');  // returns 0
pointScale('Tue');  // returns 125
pointScale('Fri');  // returns 500
```

The distance between the points can be accessed using `.step()`:

```js
pointScale.step();  // returns 125
```

Outside padding can be specified as the ratio of the padding to point spacing. For example, for the outside padding to be a quarter of the point spacing use a value of 0.25:

```js
pointScale.padding(0.25);

pointScale('Mon');  // returns 27.77...
pointScale.step();  // returns 111.11...
```

#### Further reading [Anchor link for: further reading](https://www.d3indepth.com/scales/\#further-reading)

[ColorBrewer schemes for D3](https://github.com/d3/d3-scale-chromatic)

[Mike Bostock on d3-scale](https://medium.com/@mbostock/introducing-d3-scale-61980c51545f#.lk2cs7x7k)

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Chart Shapes Guide
# D3 Shapes

_How to create commonly used chart shapes such as multi-segment lines, areas, stacked bars, stacked areas, streamgraphs, pie segments and symbols using D3. Also covers rendering to canvas._

This chapter looks at D3 functions that simplify drawing shapes such as lines:

curves:

pie chart segments:

and symbols:

### SVG [Anchor link for: svg](https://www.d3indepth.com/shapes/\#svg)

The shapes in the above examples are made up of SVG `path` elements. Each of them has a `d` attribute (path data) which defines the shape of the path.

The path data consists of a list of commands such as `M0,80L100,100L200,30L300,50L400,40L500,80` which describe the shape of the path. Each letter such as `M` or `L` describe a command such as 'move to' and 'draw a line to'. See the [SVG specification](https://www.w3.org/TR/SVG/paths.html) for more detail.

You can create path data yourself but D3 provides generator functions that do the work for you. These come in various forms:

|     |     |
| --- | --- |
| [line](https://www.d3indepth.com/shapes/#line-generator) | Generates path data for a multi-segment line (typically for line charts) |
| [area](https://www.d3indepth.com/shapes/#area-generator) | Generates path data for an area (typically for stacked line charts and streamgraphs) |
| [stack](https://www.d3indepth.com/shapes/#stack-generator) | Generates stack data from multi-series data |
| [arc](https://www.d3indepth.com/shapes/#arc-generator) | Generates path data for an arc (typically for pie charts) |
| [pie](https://www.d3indepth.com/shapes/#pie-generator) | Generates pie angle data from array of data |
| [symbol](https://www.d3indepth.com/shapes/#symbols) | Generates path data for symbols such as plus, star, diamond |

There's also a generator for creating path data from GeoJSON. This is covered in the [geographic](https://www.d3indepth.com/geographic) section.

### d3-shape [Anchor link for: d3 shape](https://www.d3indepth.com/shapes/\#d3-shape)

All the shape functions covered here are imported from the `d3-shape` module. For example:

```js
import { line } from 'd3-shape';
```

### Line generator [Anchor link for: line generator](https://www.d3indepth.com/shapes/\#line-generator)

D3's line generator produces a **path data string** given an **array of co-ordinates**.

You create a line generator using `line()`:

```js
let lineGenerator = line();
```

`line()` returns a function that accepts an array of co-ordinates and outputs a path data string.

Let's define an array of co-ordinates:

```js
let points = [\
  [0, 80],\
  [100, 100],\
  [200, 30],\
  [300, 50],\
  [400, 40],\
  [500, 80]\
];
```

and call `lineGenerator` with the array as the argument:

```js
let pathData = lineGenerator(points); // returns "M0,80L100,100L200,30L300,50L400,40L500,80"
```

`lineGenerator` creates a string of `M` (move to) and `L` (line to) commands from the array of points.

You can use `pathData` to set the `d` attribute of a `path` element:

```js
select('path')
  .attr('d', pathData);
```

#### .x and .y methods [Anchor link for: x and y methods](https://www.d3indepth.com/shapes/\#x-and-y-methods)

By default each array element represents a co-ordinate defined by a 2-dimensional array (e.g. `[0, 100]`). However you can specify how the line generator interprets each array element using the methods `.x` and `.y`.

For example suppose your data is an array of objects:

```js
let data = [\
  {value: 10},\
  {value: 50},\
  {value: 30},\
  {value: 40},\
  {value: 20},\
  {value: 70},\
  {value: 50}\
];
```

If you pass functions into the `.x` and `.y` methods of `lineGenerator` D3 will apply these functions to each array element:

```js
let xScale = scaleLinear().domain([0, 6]).range([0, 600]);
let yScale = scaleLinear().domain([0, 80]).range([150, 0]);

lineGenerator
  .x(function(d, i) {
    return xScale(i);
  })
  .y(function(d) {
    return yScale(d.value);
  });
```

The x coordinate is set using a linear scale function applied to the array index. This results in equidistant points in the x direction. The y coodinate is set using a linear scale applied to the `value` property:

> The functions passed into the `.x` and `.y` methods (and other similar methods) are known as **accessor functions**.

#### .defined() [Anchor link for: defined](https://www.d3indepth.com/shapes/\#defined)

You can configure the behaviour when there's missing data. Suppose your data has a gap in it:

```js
let points = [\
  [0, 80],\
  [100, 100],\
  null,\
  [300, 50],\
  [400, 40],\
  [500, 80]\
];
```

the line generator will raise an error.

To overcome this you can use the `.defined` method. You pass in a function that returns `true` if the data is well defined. If the function returns `false` the line generator will skip over it:

```js
lineGenerator
  .defined(function(d) {
    return d !== null;
  });
```

Now when you call `lineGenerator` it leaves a gap in the line:

#### .curve() [Anchor link for: curve](https://www.d3indepth.com/shapes/\#curve)

You can configure how the points are interpolated. For example you can interpolate each data point with a B-spline:

```js
let lineGenerator = line()
  .curve(curveCardinal);
```

Although there's a multitude of different curve types available they can be divided into two camps: those which pass through the points ( `curveLinear`, `curveCardinal`, `curveCatmullRom`, `curveMonotone`, `curveNatural` and `curveStep`) and those that don't ( `curveBasis` and `curveBundle`).

See the [curve explorer](https://www.d3indepth.com/examples-merged/shapes/curve-explorer/) for more information.

#### Rendering to canvas [Anchor link for: rendering to canvas](https://www.d3indepth.com/shapes/\#rendering-to-canvas)

By default the shape generators output SVG path data. However they can be configured to draw to a canvas element using the `.context()` function:

```js
let context = select('canvas').node().getContext('2d');

lineGenerator.context(context);

context.strokeStyle = '#999';
context.beginPath();
lineGenerator(points);
context.stroke();
```

#### Radial line [Anchor link for: radial line](https://www.d3indepth.com/shapes/\#radial-line)

The radial line generator is similar to the line generator but the points are transformed by **angle** (working clockwise from 12 o'clock) and **radius**, rather than `x` and `y`:

```js
let radialLineGenerator = radialLine();

let points = [\
  [0, 80],\
  [Math.PI * 0.25, 80],\
  [Math.PI * 0.5, 30],\
  [Math.PI * 0.75, 80],\
  [Math.PI, 80],\
  [Math.PI * 1.25, 80],\
  [Math.PI * 1.5, 80],\
  [Math.PI * 1.75, 80],\
  [Math.PI * 2, 80]\
];

let pathData = radialLineGenerator(points);
```

The `radialLine` generator also has methods `.angle` and `.radius` into which you can pass accessor functions. These are handy if you've an array of objects:

```js
let points = [\
  {a: 0, r: 80},\
  {a: Math.PI * 0.25, r: 80},\
  {a: Math.PI * 0.5, r: 30},\
  {a: Math.PI * 0.75, r: 80},\
  ...\
];

radialLineGenerator
  .angle(function(d) {
    return d.a;
  })
  .radius(function(d) {
    return d.r;
  });

let pathData = radialLineGenerator(points);
```

### Area generator [Anchor link for: area generator](https://www.d3indepth.com/shapes/\#area-generator)

The area generator outputs path data that defines an area between two lines. By default it generates the area between `y=0` and a multi-segment line defined by an array of points:

```js
let areaGenerator = area();

let points = [\
  [0, 80],\
  [100, 100],\
  [200, 30],\
  [300, 50],\
  [400, 40],\
  [500, 80]\
];

let pathData = areaGenerator(points);
```

You can configure the baseline using the `.y0` method:

```js
areaGenerator.y0(150);
```

You can also pass accessor functions into the `.y0` and `.y1` methods:

```js
let yScale = scaleLinear().domain([0, 100]).range([200, 0]);

let points = [\
  {x: 0, low: 30, high: 80},\
  {x: 100, low: 80, high: 100},\
  {x: 200, low: 20, high: 30},\
  {x: 300, low: 20, high: 50},\
  {x: 400, low: 10, high: 40},\
  {x: 500, low: 50, high: 80}\
];

areaGenerator
  .x(function(d) {
    return d.x;
  })
  .y0(function(d) {
    return yScale(d.low);
  })
  .y1(function(d) {
    return yScale(d.high);
  });
```

> Typically `.y0` defines the baseline and `.y1` the top line.

As with the line generator you can specify the way in which the points are interpolated using `.curve()`, handle missing data using `.defined()` and render to canvas using `.context()`.

#### Radial area [Anchor link for: radial area](https://www.d3indepth.com/shapes/\#radial-area)

The radial area generator is similar to the area generator but the points are transformed by **angle** (working clockwise from 12 o'clock) and **radius**, rather than `x` and `y`:

```js
let points = [\
  {angle: 0, r0: 20, r1: 80},\
  {angle: Math.PI * 0.25, r0: 20, r1: 40},\
  {angle: Math.PI * 0.5, r0: 20, r1: 80},\
  {angle: Math.PI * 0.75, r0: 20, r1: 40},\
  {angle: Math.PI, r0: 20, r1: 80},\
  {angle: Math.PI * 1.25, r0: 20, r1: 40},\
  {angle: Math.PI * 1.5, r0: 20, r1: 80},\
  {angle: Math.PI * 1.75, r0: 20, r1: 40},\
  {angle: Math.PI * 2, r0: 20, r1: 80}\
];

let radialAreaGenerator = radialArea()
  .angle(function(d) {
    return d.angle;
  })
  .innerRadius(function(d) {
    return d.r0;
  })
  .outerRadius(function(d) {
    return d.r1;
  });
```

### Stack generator [Anchor link for: stack generator](https://www.d3indepth.com/shapes/\#stack-generator)

The stack generator takes an array of objects and generates an array for each object property. Each array contains **lower and upper values** for each data point. The lower and upper values are computed so that each series is stacked on top of the previous series.

In this example we've an array of objects. We create a stack generator using `stack`. We use its `.keys` method to pass in the property keys which we'd like to stack. In this case we're stacking `apricots`, `blueberries` and `cherries`:

```js
let data = [\
  {day: 'Mon', apricots: 120, blueberries: 180, cherries: 100},\
  {day: 'Tue', apricots: 60,  blueberries: 185, cherries: 105},\
  {day: 'Wed', apricots: 100, blueberries: 215, cherries: 110},\
  {day: 'Thu', apricots: 80,  blueberries: 230, cherries: 105},\
  {day: 'Fri', apricots: 120, blueberries: 240, cherries: 105}\
];

let stack = stack()
  .keys(['apricots', 'blueberries', 'cherries']);

let stackedSeries = stack(data);

// stackedSeries = [\
//   [ [0, 120],   [0, 60],   [0, 100],    [0, 80],    [0, 120] ],   // Apricots\
//   [ [120, 300], [60, 245], [100, 315],  [80, 310],  [120, 360] ], // Blueberries\
//   [ [300, 400], [245, 350], [315, 425], [310, 415], [360, 465] ]  // Cherries\
// ]
```

The data output by the stack generator can be used however you like, but typically it'll be used to produce stacked bar charts:

or when used in conjunction with the area generator, stacked line charts:

#### .order() [Anchor link for: order](https://www.d3indepth.com/shapes/\#order)

The order of the stacked series can be configured using `.order()`:

```js
stack.order(stackOrderInsideOut);
```

Each series is summed and then sorted according to the chosen order. The possible orders are:

|     |     |
| --- | --- |
| stackOrderNone | (Default) Series in same order as specified in .keys() |
| stackOrderAscending | Smallest series at the bottom |
| stackOrderDescending | Largest series at the bottom |
| stackOrderInsideOut | Largest series in the middle |
| stackOrderReverse | Reverse of stackOrderNone |

#### .offset() [Anchor link for: offset](https://www.d3indepth.com/shapes/\#offset)

By default the stacked series have a baseline of zero. However you can configure the offset of the stack generator to achieve different effects. For example you can normalise the stacked series so that they fill the same height:

```js
stack.offset(stackOffsetExpand);
```

The available offsets are:

|     |     |
| --- | --- |
| stackOffsetNone | (Default) No offset |
| stackOffsetExpand | Sum of series is normalised (to a value of 1) |
| stackOffsetSilhouette | Center of stacks is at y=0 |
| stackOffsetWiggle | Wiggle of layers is minimised (typically used for streamgraphs) |

Here's a streamgraph example using `stackOffsetWiggle`:

### Arc generator [Anchor link for: arc generator](https://www.d3indepth.com/shapes/\#arc-generator)

Arc generators produce path data from angle and radius values. An arc generator is created using:

```js
let arcGenerator = arc();
```

It can then be passed an object containing `startAngle`, `endAngle`, `innerRadius` and `outerRadius` properties to produce the path data:

```js
let pathData = arcGenerator({
  startAngle: 0,
  endAngle: 0.25 * Math.PI,
  innerRadius: 50,
  outerRadius: 100
});

// pathData is "M6.123233995736766e-15,-100A100,100,0,0,1,70.71067811865476,-70.710678
// 11865474L35.35533905932738,-35.35533905932737A50,50,0,0,0,3.061616997868383e-15,-50Z"
```

> `startAngle` and `endAngle` are measured clockwise from the 12 o'clock in radians.

#### Configuration [Anchor link for: configuration](https://www.d3indepth.com/shapes/\#configuration)

You can configure `innerRadius`, `outerRadius`, `startAngle`, `endAngle` so that you don't have to pass them in each time:

```js
arcGenerator
  .innerRadius(20)
  .outerRadius(100);

pathData = arcGenerator({
  startAngle: 0,
  endAngle: 0.25 * Math.PI
});

// pathData is "M6.123233995736766e-15,-100A100,100,0,0,1,70.71067811865476,-70.71067811
// 865474L14.142135623730951,-14.14213562373095A20,20,0,0,0,1.2246467991473533e-15,-20Z"
```

You can also configure corner radius ( `cornerRadius`) and the padding between arc segments ( `padAngle` and `padRadius`):

```js
arcGenerator
  .padAngle(.02)
  .padRadius(100)
  .cornerRadius(4);
```

Arc padding takes two parameters `padAngle` and `padRadius` which when multiplied together define the distance between adjacent segments. Thus in the example above, the padding distance is `0.02 * 100 = 2`. Note that the padding is calculated to maintain (where possible) parallel segment boundaries.

> You might ask why there isn't a single parameter padDistance for defining the padding distance. It's split into two parameters so that the pie generator (see later) doesn't need to concern itself with radius.

#### Accessor functions [Anchor link for: accessor functions](https://www.d3indepth.com/shapes/\#accessor-functions)

You can define accessor functions for `startAngle`, `endAngle`, `innerRadius` and `outerRadius`. For example:

```js
arcGenerator
  .startAngle(function(d) {
    return d.startAngleOfMyArc;
  })
  .endAngle(function(d) {
    return d.endAngleOfMyArc;
  });

arcGenerator({
  startAngleOfMyArc: 0,
  endAngleOfMyArc: 0.25 * Math.PI
});
```

#### Centroid [Anchor link for: centroid](https://www.d3indepth.com/shapes/\#centroid)

It's sometimes useful to calculate the centroid of an arc, such as when positioning labels, and D3 has a function `.centroid()` for doing this:

```js
arcGenerator.centroid({
  startAngle: 0,
  endAngle: 0.25 * Math.PI
});
// returns [22.96100594190539, -55.43277195067721]
```

Here's an example where `.centroid()` is used to compute the label positions:

ABCDE

### Pie generator [Anchor link for: pie generator](https://www.d3indepth.com/shapes/\#pie-generator)

The pie generator goes hand in hand with the arc generator. Given an array of data, the pie generator will output an array of objects containing the original data augmented by **start** and **end angles**:

```js
let pieGenerator = pie();
let data = [10, 40, 30, 20, 60, 80];
let arcData = pieGenerator(data);

// arcData is an array of objects: [\
//   {\
//     data: 10,\
//     endAngle: 6.28...,\
//     index: 5,\
//     padAngle: 0,\
//     startAngle: 6.02...,\
//     value: 10\
//   },\
//   ...\
// ]
```

You can then use an arc generator to create the path strings:

```js
let arcGenerator = arc()
  .innerRadius(20)
  .outerRadius(100);

select('g')
  .selectAll('path')
  .data(arcData)
  .enter()
  .append('path')
  .attr('d', arcGenerator);
```

Notice that the output of `pieGenerator` contains the properties `startAngle` and `endAngle`. These are the same properties required by `arcGenerator`.

The pie generator has a number of configuration functions including `.padAngle()`, `.startAngle()`, `.endAngle()` and `.sort()`. `.padAngle()` specifies an angular padding (in radians) between neighbouring segments.

`.startAngle()` and `.endAngle()` configure the start and end angle of the pie chart. This allows, for example, the creation of semi-circular pie charts:

```js
let pieGenerator = pie()
  .startAngle(-0.5 * Math.PI)
  .endAngle(0.5 * Math.PI);
```

By default the segment start and end angles are specified such that the segments are in descending order. However we can change the sort order using `.sort`:

```js
let pieGenerator = pie()
  .value(function(d) {return d.quantity;})
  .sort(function(a, b) {
    return a.name.localeCompare(b.name);
  });

let fruits = [\
  {name: 'Apples', quantity: 20},\
  {name: 'Bananas', quantity: 40},\
  {name: 'Cherries', quantity: 50},\
  {name: 'Damsons', quantity: 10},\
  {name: 'Elderberries', quantity: 30},\
];
```

ApplesBananasCherriesDamsonsElderberries

### Symbols [Anchor link for: symbols](https://www.d3indepth.com/shapes/\#symbols)

The symbol generator produces path data for symbols commonly used in data visualisation:

```js
let symbolGenerator = symbol()
  .type(symbolStar)
  .size(80);

let pathData = symbolGenerator();
```

You can use `pathData` to define the `d` attribute of a path element:

```js
select('path')
  .attr('d', pathData);
```

Here's a simple chart using the symbol generator:

D3 provides a number of symbol types:

symbolCirclesymbolCrosssymbolDiamondsymbolSquaresymbolStarsymbolTrianglesymbolWye

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Chord Diagrams
# D3 Chord Diagrams

Chord diagrams visualise links (or flows) between a group of nodes, where each flow has a numeric value. For example, they can show [migration flows](http://www.global-migration.info/) between countries. (Personally I find them difficult to interpret!)

The data needs to be in the form of an n x n matrix (where n is the number of items):

```js
let data = [\
  [10, 20, 30],\
  [40, 60, 80],\
  [100, 200, 300]\
];
```

The first row represents flows from the 1st item to the 1st, 2nd and 3rd items etc.

You create the layout using `chord` (imported from `d3-chord`):

```js
let chordGenerator = chord();
```

and you configure it using `.padAngle()` (to set the angle between adjacent groups in radians), `.sortGroups()` (to specify the order of the groups), `.sortSubgroups()` (to sort within each group) and `.sortChords()` to determine the z order of the chords.

Apply the layout using:

```js
let chords = chordGenerator(data);
```

which returns an array of chords. Each element of the array is an object with `source` and `target` properties. Each `source` and `target` has `startAngle` and `endAngle` properties which will define the shape of each chord.

We use the `ribbon` shape generator which converts the chord properties into path data (see the [Shapes chapter](https://www.d3indepth.com/shapes) for more information on shape generators).

```js
let ribbonGenerator = ribbon().radius(200);

select('g')
  .selectAll('path')
  .data(chords)
  .join('path')
  .attr('d', ribbonGenerator)
```

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Force Layout Guide
# D3 Force layout

_D3's force layout uses physics based rules to position visual elements. This article shows how to use D3's force layout and how to use it to create network visualisations and circle clusters._

D3's force layout uses a **physics based simulator** for positioning visual elements.

Forces can be set up between elements, for example:

- all elements can be configured to repel one another
- elements can be attracted to center(s) of gravity
- linked elements can be set a fixed distance apart (e.g. for network visualisation)
- elements can be configured to avoid intersecting one another (collision detection)

The force layout lets us position elements in a way that would be difficult using other approaches.

Here's an example of a force layout where we've a number of circles (each of which has a category `A`, `B` or `C`) and we add the following forces:

- all circles attract one another (to clump circles together)
- collision detection (to stop circles overlapping)
- circles are attracted to one of three centers ( `A`, `B` or `C`)

The force layout requires a larger amount of computation (typically requiring a few seconds of time) than other D3 layouts and and the solution is calculated in a **step by step (iterative)** manner. Usually the positions of the SVG/HTML elements are updated as the simulation iterates, which is why we see the circles jostling into position.

### Setting up a force simulation [Anchor link for: setting up a force simulation](https://www.d3indepth.com/force-layout/\#setting-up-a-force-simulation)

Broadly speaking there are 4 steps to setting up a force simulation:

- create an array of objects
- call `forceSimulation`, passing in the array of objects
- add one or more force functions (e.g. `forceManyBody`, `forceCenter`, `forceCollide`) to the system
- set up a callback function to update the element positions after each tick

All of D3's force functions are imported from `d3-force`.

Let's start with a minimal example:

```js
let width = 300, height = 300
let nodes = [{}, {}, {}, {}, {}]

let simulation = forceSimulation(nodes)
  .force('charge', forceManyBody())
  .force('center', forceCenter(width / 2, height / 2))
  .on('tick', ticked);
```

Here we've created a simple array of 5 objects and have added two force functions `forceManyBody` and `forceCenter` to the system. (The first of these makes the elements repel each other while the second attracts the elements towards a centre point.)

Each time the simulation iterates the function `ticked` will be called. This function joins the `nodes` array to `circle` elements and updates their positions:

```js
function ticked() {
  let u = select('svg')
    .selectAll('circle')
    .data(nodes)
    .join('circle')
    .attr('r', 5)
    .attr('cx', function(d) {
      return d.x
    })
    .attr('cy', function(d) {
      return d.y
    });
}
```

The power and flexibility of the force simulation is centred around **force functions** which adjust the position and velocity of elements to achieve a number of effects such as attraction, repulstion and collision detection.

You can define your own force functions but D3 comes with a number of useful ones (imported from `d3-force`):

- `forceCenter` (for setting the center of gravity of the system)
- `forceManyBody` (for making elements attract or repel one another)
- `forceCollide` (for preventing elements overlapping)
- `forceX` and `forceY` (for attracting elements to a given point)
- `forceLink` (for creating a fixed distance between connected elements)

Force functions are added to the simulation using `.force()` where the first argument is a user defined id and the second argument the force function:

```js
simulation.force('charge', forceManyBody())
```

Let's look at the built-in force functions one by one.

### forceCenter [Anchor link for: forcecenter](https://www.d3indepth.com/force-layout/\#forcecenter)

`forceCenter` is useful (if not essential) for centering your elements as a whole about a center point. (Without it elements might disappear off the page.)

It can either be initialised with a center position:

```js
forceCenter(100, 100)
```

or using the configuration functions `.x()` and `.y()`:

```js
forceCenter().x(100).y(100)
```

You can add it to the system using:

```js
simulation.force('center', forceCenter(100, 100))
```

See the next example ( `forceManyBody`) for an example implementation.

### forceManyBody [Anchor link for: forcemanybody](https://www.d3indepth.com/force-layout/\#forcemanybody)

`forceManyBody` causes all elements to attract or repel one another. The strength of the attraction or repulsion can be set using `.strength()` where a positive value will cause elements to attract one another while a negative value causes elements to repel each other. The default value is `-30`.

```js
simulation.force('charge', forceManyBody().strength(-20))
```

> When creating network diagrams we typically want the elements to repel one another but for visualisations where elements are clumped together, attractive forces are necessary.

### forceCollide [Anchor link for: forcecollide](https://www.d3indepth.com/force-layout/\#forcecollide)

`forceCollide` is used to stop circular elements overlapping and is particularly useful when 'clumping' circles together.

The radius of the elements is specified by passing an accessor function into `forceCollide`'s `.radius` method. This function's first parameter `d` is the joined data from which you can derive the radius.

For example:

```js
let numNodes = 100
let nodes = range(numNodes).map(function(d) {
  return {radius: Math.random() * 25}
})

let simulation = forceSimulation(nodes)
  .force('charge', forceManyBody().strength(5))
  .force('center', forceCenter(width / 2, height / 2))
  .force('collision', forceCollide().radius(function(d) {
    return d.radius
  }))
```

In this example, `forceManyBody` pushes all the nodes together, `forceCenter` helps keep the nodes in the center of the container and `forceCollide` stops the nodes intersecting.

### forceX and forceY [Anchor link for: forcex and forcey](https://www.d3indepth.com/force-layout/\#forcex-and-forcey)

`forceX` and `forceY` cause elements **to be attracted towards** specified position(s). We can use a single center for all elements or apply the force on a per-element basis. The strength of attraction can be configured using `.strength()`.

For example suppose you have a number of elements, each of which has a property `category` that has value `0`, `1` or `2`. You can add a `forceX` force function to attract the elements to an x-coordinate of `100`, `300` or `500` based on the element's category:

```js
let xCenter = [100, 300, 500];

let simulation = forceSimulation(nodes)
  .force('charge', forceManyBody().strength(5))
  .force('x', forceX().x(function(d) {
    return xCenter[d.category];
  }))
  .force('collision', forceCollide().radius(function(d) {
    return d.radius;
  }));
```

In this example, `forceManyBody` pushes all the nodes together, `forceX` attracts the nodes to particular x-coordinates and `forceCollide` stops the nodes intersecting.

If our data has a numeric dimension we can use `forceX` or `forceY` to position elements along an axis:

```js
let simulation = forceSimulation(nodes)
  .force('charge', forceManyBody().strength(5))
  .force('x', forceX().x(function(d) {
    return xScale(d.value);
  }))
  .force('y', forceY().y(function(d) {
    return 0;
  }))
  .force('collision', forceCollide().radius(function(d) {
    return d.radius;
  }));
```

> Use the above with caution because the x position of the elements is not guaranteed to be exact.

### forceLink [Anchor link for: forcelink](https://www.d3indepth.com/force-layout/\#forcelink)

`forceLink` pushes linked elements to be a **fixed distance apart**. It requires an **array of links** that specify which elements you'd like to link together. Each link object specifies a source and target element, where the value is the element's array index:

```js
let links = [\
  {source: 0, target: 1},\
  {source: 0, target: 2},\
  {source: 0, target: 3},\
  {source: 1, target: 6},\
  {source: 3, target: 4},\
  {source: 3, target: 7},\
  {source: 4, target: 5},\
  {source: 4, target: 7}\
]
```

You can then pass your links array into the `forceLink` function using `.links()`:

```js
let simulation = forceSimulation(nodes)
  .force('charge', forceManyBody().strength(-100))
  .force('center', forceCenter(width / 2, height / 2))
  .force('link', forceLink().links(links));
```

ABCDEFGH

In this example, `forceManyBody` pushes the nodes apart, `forceCenter` helps keep the nodes centered with the container and `forceLink` maintains a constant distance between linked nodes.

The distance and strength of the linked elements can be configured using `.distance()` (default value is 30) and `.strength()`.

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Geographic Mapping
# Making maps with D3

This page looks at D3's approach to rendering geographic information.

As an example, the globe below is drawn using D3. A GeoJSON file is loaded and D3 is used to project the geographic data and draw it on a Canvas element:

D3's approach differs to so called raster methods such as [Leaflet](http://leafletjs.com/) and Google Maps. These **pre-render map features as image tiles** and these are loaded from a web server and pieced together in the browser to form a map.

Typically D3 requests **vector geographic information** in the form of GeoJSON and **renders this to SVG or Canvas** in the browser.

Raster maps often look more like traditional print maps where a lot of detail (e.g. place names, roads, rivers etc.) can be shown without an impact on performance. However, dynamic content such as animation and interaction is more easily implemented using a vector approach. (It's also quite common to combine the two approaches.)

### D3 mapping concepts [Anchor link for: d3 mapping concepts](https://www.d3indepth.com/geographic/\#d3-mapping-concepts)

The 3 concepts that are key to understanding map creation using D3 are:

- **GeoJSON** (a JSON-based format for specifying geographic data)
- **projections** (functions that convert from latitude/longitude co-ordinates to x & y co-ordinates)
- **geographic path generators** (functions that convert GeoJSON shapes into SVG or Canvas paths)

#### GeoJSON [Anchor link for: geojson](https://www.d3indepth.com/geographic/\#geojson)

GeoJSON is a standard for representing geographic data using the JSON format and the full specification is at [geojson.org](http://geojson.org/).

Here's a typical GeoJSON object:

```json
{
  "type": "FeatureCollection",
  "features": [\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Africa"\
      },\
      "geometry": {\
        "type": "Polygon",\
        "coordinates": [[[-6, 36], [33, 30], ... , [-6, 36]]]\
      }\
    },\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Australia"\
      },\
      "geometry": {\
        "type": "Polygon",\
        "coordinates": [[[143, -11], [153, -28], ... , [143, -11]]]\
      }\
    },\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Timbuktu"\
      },\
      "geometry": {\
        "type": "Point",\
        "coordinates": [-3.0026, 16.7666]\
      }\
    }\
  ]
}
```

In the above object there's a FeatureCollection containing an array of 3 features:

- Africa
- Australia
- the city of Timbuktu

Each feature consists of **geometry** (simple polygons in the case of the countries and a point for Timbuktu) and **properties**.

Properties can contain any information about the feature such as name, id, and other data such as population, GDP etc.

D3 takes care of most of the detail when rendering GeoJSON so you only need a basic understanding of GeoJSON to get started with D3 mapping.

#### Projections [Anchor link for: projections](https://www.d3indepth.com/geographic/\#projections)

A projection function takes a longitude and latitude co-ordinate (in the form of an array `[lon, lat]`) and transforms it into an x and y co-ordinate:

```js
function projection( lonLat ) {
  let x = ... // some formula here to calculate x
  let y = ... // some formula here to calculate y
  return [x, y];
}

projection( [-3.0026, 16.7666] )
// returns [474.7594743879618, 220.7367625635119]
```

Projection mathematics can get quite complex but fortunately D3 provides a large number of projection functions.

For example you can create an equi-rectangular projection function using:

```js
let projection = geoEquirectangular();

projection( [-3.0026, 16.7666] )
// returns [474.7594743879618, 220.7367625635119]
```

We'll look at projections in more detail later.

#### Geographic path generators [Anchor link for: geographic path generators](https://www.d3indepth.com/geographic/\#geographic-path-generators)

A geographic path generator is a function that takes a GeoJSON object and converts it into an SVG path string. (In fact, it's just another type of [shape generator](https://www.d3indepth.com/shapes).)

You can create a generator using the method `.geoPath` and configure it with a projection function:

```js
let projection = geoEquirectangular();

let geoGenerator = geoPath()
  .projection(projection);

let geoJson = {
  "type": "Feature",
  "properties": {
    "name": "Africa"
  },
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[-6, 36], [33, 30], ... , [-6, 36]]]
  }
}

geoGenerator(geoJson);
// returns "M464.0166237760863,154.09974265651798L491.1506253268278,154.8895088551978 ... L448.03311471280136,183.1346693994119Z"
```

As usual with [shape generators](https://www.d3indepth.com/shapes) the generated path string is used to set the `d` attribute on an SVG `path` element.

#### Putting it all together [Anchor link for: putting it all together](https://www.d3indepth.com/geographic/\#putting-it-all-together)

Given some **GeoJSON**, a **projection function** and a **geographic path generator** you can create a basic map:

```js
let geoJson = {
  "type": "FeatureCollection",
  "features": [\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Africa"\
      },\
      "geometry": {\
        "type": "Polygon",\
        "coordinates": [[[-6, 36], [33, 30], ... , [-6, 36]]]\
      }\
    },\
    ...\
  ]
}

let projection = geoEquirectangular();

let geoGenerator = geoPath()
  .projection(projection);

// Join the FeatureCollection's features array to path elements
let u = select('#content g.map')
  .selectAll('path')
  .data(geojson.features)
  .join('path')
  .attr('d', geoGenerator);
```

`geoJson.features` is an array of features. This array is joined to `path` elements. The `d` attribute is set using the function `geoGenerator`. This receives a feature as its first parameter and outputs a path string.

The last line may look like magic but is the equivalent of:

```
  .attr('d', function(d) {
    return geoGenerator(d);
  });

```

In this case the parameter `d` is a GeoJSON feature.

> To keep things simple the GeoJSON in the above example uses just a few co-ordinates to define the country boundaries.

The above example shows the essence of creating maps using D3 and I recommend spending time to understand each concept (GeoJSON, projections and geo generators) and how they fit together.

Now that we've covered the basics we'll look at each concept in more detail.

### GeoJSON [Anchor link for: geojson 1](https://www.d3indepth.com/geographic/\#geojson-1)

GeoJSON is a JSON-based structure for specifying geographic data. More often than not it's converted from shapefile data (a geospatial vector data format widely used in the GIS field) using tools such as [mapshaper](http://mapshaper.org/), [ogr2ogr](http://www.gdal.org/ogr2ogr.html), [shp2json](https://github.com/mbostock/shapefile) or [QGIS](http://www.qgis.org/en/site/).

A popular source of world map shapefiles is [Natural Earth](http://www.naturalearthdata.com/) and if starting out I recommend trying out [mapshaper](http://mapshaper.org/) for importing shapefiles and exporting as GeoJSON. It can also filter by properties (e.g. if you wanted to filter countries by continent). For a more in depth look at conversion look at Mike Bostock's [Let's Make a Map](https://bost.ocks.org/mike/map/) tutorial.

You can create maps without understanding the GeoJSON specification in minute detail because tools such as mapshaper and D3 do such a good job of abstracting away the detail. However, if you did want to understand GeoJSON in greater depth I recommend checking out the [official specification](http://geojson.org/).

So far we've embedded a GeoJSON object in our example files. In practice the GeoJSON would be in a separate file and loaded using an ajax request. We cover requests in more detail in the [requests chapter](https://www.d3indepth.com/requests) but for the remainder of this chapter we'll load a GeoJSON file using:

```js
json('ne_110m_land.json', function(err, json) {
  createMap(json);
})
```

It's worth mentioning TopoJSON which is another JSON based standard for describing geographic data and tends to result in significantly smaller file sizes. It requires a bit more work to use, and we don't cover it in this chapter. However for further information check out the [documentation](https://github.com/topojson/topojson).

### Projections [Anchor link for: projections 1](https://www.d3indepth.com/geographic/\#projections-1)

There are numerous (if not infinite) ways of converting (or 'projecting') a point on a sphere (e.g. the earth) to a point on a flat surface (e.g. a screen) and people have written countless articles (such as [this](http://www.progonos.com/furuti/MapProj/Normal/TOC/cartTOC.html) one) on the pros and cons of different projections.

In short there is no perfect projection as every projection will distort shape, area, distance and/or direction. Choosing a projection is a case of choosing which property you don't want to be distorted and accepting that there'll be distortion in the other properties (or choose a projection that strives for a balanced approach). For example, if it's important that the size of countries are represented accurately then choose a projection that strives to preserve area (probably to the cost of shape, distance and direction).

D3 has a number of core projections that should cover most use cases:

- `geoAzimuthalEqualArea`
- `geoAzimuthalEquidistant`
- `geoGnomonic`
- `geoOrthographic`
- `geoStereographic`
- `geoAlbers`
- `geoConicConformal`
- `geoConicEqualArea`
- `geoConicEquidistant`
- `geoEquirectangular`
- `geoMercator`
- `geoTransverseMercator`

Each of these projection functions is imported from `d3-geo`.

Some projections preserve area (e.g. `geoAzimuthalEqualArea` & `geoConicEqualArea`), others distance (e.g. `geoAzimuthalEquidistant` & `geoConicEquidistant`) and others relative angles (e.g. `geoEquirectangular` & `geoMercator`). For a more in depth discussion of the pros and cons of each projection try resources such as Carlos A. Furuti's [Map Projection Pages](http://www.progonos.com/furuti/MapProj/Normal/TOC/cartTOC.html).

The grid below shows each core projection on a world map together with a longitude/latitude grid and equal radius circles.

#### Projection functions [Anchor link for: projection functions](https://www.d3indepth.com/geographic/\#projection-functions)

A projection function takes input `[longitude, latitude]` and outputs a pixel co-ordinate `[x, y]`.

> Be careful to note the order of longitude and latitude in the above array!

You're free to write your own projection functions but much easier is to ask D3 to make one for you. To do this choose a projection method (e.g. `geoAzimuthalEqualArea`), call it and it'll return a projection function:

```js
let projection = geoAzimuthalEqualArea();

projection( [-3.0026, 16.7666] );
// returns [473.67353385539417, 213.6120079887163]
```

The core projections have configuration functions for setting the following parameters:

|     |     |
| --- | --- |
| [scale](https://www.d3indepth.com/geographic/#scale) | Scale factor of the projection |
| [center](https://www.d3indepth.com/geographic/#center) | Projection center \[longitude, latitude\] |
| [translate](https://www.d3indepth.com/geographic/#translate) | Pixel \[x,y\] location of the projection center |
| [rotate](https://www.d3indepth.com/geographic/#rotate) | Rotation of the projection \[lambda, phi, gamma\] (or \[yaw, pitch, roll\]) |

The precise meaning of each parameter is dependent on the mathematics behind each projection but broadly speaking:

- scale specifies the **scale factor** of the projection. The higher the number the larger the map.
- center specifies the **center of projection** (with a `[lon, lat]` array)
- translate specifies where the **center of projection is located on the screen** (with a `[x, y]` array)
- rotate specifies the **rotation of the projection** (with a `[λ, φ, γ]` array) where the parameters correspond to yaw, pitch and roll, respectively:

![](https://www.d3indepth.com/img/geo/projection-rotation.svg)

For example you can create and configure a projection function such that Timbuktu is centred in a 960x500 map using:

```js
let projection = geoAzimuthalEqualArea()
  .scale(300)
  .center([-3.0026, 16.7666])
  .translate([480, 250]);
```

To get a feel for how each parameter behaves use the projection explorer below. The (equal radius) circles and grid allow you to assess the projection's distortion of area and angle.

AzimuthalEqualAreaAzimuthalEquidistantGnomonicOrthographicStereographicAlbersConicConformalConicEqualAreaConicEquidistantEquirectangularMercatorTransverseMercator

scale (120)

0400

center (lon) (0)

-180180

center (lat) (0)

-9090

translate (x) (480)

0960

translate (y) (250)

0500

rotate (λ) (0)

-180180

rotate (φ) (0)

-180180

rotate (γ) (0)

-180180

#### .invert() [Anchor link for: invert](https://www.d3indepth.com/geographic/\#invert)

You can convert a pixel co-ordinate `[x, y]` to a longitude/latitude array using the projection's `.invert()` method:

```js
let projection = geoAzimuthalEqualArea();

projection( [-3.0026, 16.7666] )
// returns [473.67353385539417, 213.6120079887163]

projection.invert( [473.67353385539417, 213.6120079887163] )
// returns [-3.0026, 16.766]
```

#### Fitting [Anchor link for: fitting](https://www.d3indepth.com/geographic/\#fitting)

Given a GeoJSON object, a projection's `.fitExtent()` method sets the projection's **scale** and **translate** such that the geometry fits within a given bounding box:

```js
projection.fitExtent([[0, 0], [900, 500]], geojson);
```

The first argument of `.fitExtent` is an array containing two coordinates: the top left point ( `[x, y]`) of the bounding box and the size ( `[width, height]`) of the bounding box. The second argument is a GeoJSON object.

In the example below the canvas element has a light grey background and the bounding box into which we're fitting the geoJSON is shown as a dotted outline. The following code is used to fit the geometry within the bounding box:

```js
projection.fitExtent([[20, 20], [620, 420]], geojson);
```

If your bounding box's top left corner is at `[0, 0]` you can omit the top left coordinate and just supply the width and height:

```js
projection.fitSize([900, 500], geojson);
```

### Geographic path generators [Anchor link for: geographic path generators 1](https://www.d3indepth.com/geographic/\#geographic-path-generators-1)

A geographic path generator is a function that transforms **GeoJSON into an SVG path string** (or into canvas element calls):

```js
geoGenerator(geoJson);
// e.g. returns a SVG path string "M464.01,154.09L491.15,154.88 ... L448.03,183.13Z"
```

You create the generator using `geoPath` (imported from `d3-geo`). You must configure its projection type:

```js
let projection = geoEquirectangular();

let geoGenerator = geoPath()
  .projection(projection);
```

You can now use the generator to help create an SVG or canvas map. The SVG option is a bit easier to implement, especially when it comes to user interaction (because event handlers and hover states can be added).

The canvas approach requires a bit more work but is typically faster to render and more memory efficient.

#### Rendering SVG [Anchor link for: rendering svg](https://www.d3indepth.com/geographic/\#rendering-svg)

To render an SVG map you:

- [join](https://www.d3indepth.com/datajoins) a GeoJSON features array to SVG `path` elements
- update each `path` element's `d` attribute using the geographic path generator

For example:

```js
let geoJson = {
  "type": "FeatureCollection",
  "features": [\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Africa"\
      },\
      "geometry": {\
        "type": "Polygon",\
        "coordinates": [[[-6, 36], [33, 30], ... , [-6, 36]]]\
      }\
    },\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Australia"\
      },\
      "geometry": {\
        "type": "Polygon",\
        "coordinates": [[[143, -11], [153, -28], ... , [143, -11]]]\
      }\
    },\
    {\
      "type": "Feature",\
      "properties": {\
        "name": "Timbuktu"\
      },\
      "geometry": {\
        "type": "Point",\
        "coordinates": [-3.0026, 16.7666]\
      }\
    }\
  ]
}

let projection = geoEquirectangular();

let geoGenerator = geoPath()
  .projection(projection);

// Join the FeatureCollection's features array to path elements
let u = select('#content g.map')
  .selectAll('path')
  .data(geojson.features)
  .join('path')
  .attr('d', geoGenerator);
```

`geoJson.features` is an array of features. This array is joined to `path` elements. The `d` attribute is set using the function `geoGenerator`. This receives a feature as its first parameter and outputs a path string.

#### Rendering to canvas [Anchor link for: rendering to canvas](https://www.d3indepth.com/geographic/\#rendering-to-canvas)

To render to a canvas element you pass the `canvas` DOM element into the generator's `context` method:

```js
let context = select('#content canvas')
  .node()
  .getContext('2d');

let geoGenerator = geoPath()
  .projection(projection)
  .context(context);
```

> The `.node` method returns the first DOM element of a selection.

You then begin a canvas path (using `context.beginPath()`) and call `geoGenerator` which will produce the necessary canvas calls:

```js
context.beginPath();
geoGenerator({type: 'FeatureCollection', features: geojson.features})
context.stroke();
```

#### Lines and arcs [Anchor link for: lines and arcs](https://www.d3indepth.com/geographic/\#lines-and-arcs)

The geographic path generator is clever enough to distinguish between polygonal (typically for geographic areas) and point (typically for lon/lat locations) features. As can be seen in the above examples it renders polygons as line segments and points as arcs.

You can set the radius of the circles using `.pointRadius()`:

```js
let geoGenerator = geoPath()
  .pointRadius(5)
  .projection(projection);
```

#### Path geometry [Anchor link for: path geometry](https://www.d3indepth.com/geographic/\#path-geometry)

The geographic path generator can also be used to compute the **area** (in pixels), **centroid**, **bounding box** and **path length** (in pixels) of a projected GeoJSON feature:

```js
let feature = geojson.features[0];

// Compute the feature's area (in pixels)
geoGenerator.area(feature);
// returns 30324.86518469876

// Compute the feature's centroid (in pixel co-ordinates)
geoGenerator.centroid(feature);
// returns [266.9510120424504, 127.35819206325564]

// Compute the feature's bounds (in pixel co-ordinates)
geoGenerator.bounds(feature);
// returns [[140.6588054321928, 24.336293856408275], [378.02358370342165, 272.17304763960306]]

// Compute the path length (in pixels)
geoGenerator.measure(feature);
// returns 775.7895349902461
```

This example shows the area and length of a hovered path. It also draws the path's centroid and bounding box:

Hover over a country

### Shapes [Anchor link for: shapes](https://www.d3indepth.com/geographic/\#shapes)

If you need to add lines and/or circles to a map you can add features to the GeoJSON.

Lines can be added as a LineString feature and will be projected into great-arcs (i.e. the shortest distance across the surface of the globe).

Here's an example where a line is added between London and New York:

```js
geoGenerator({
  type: 'Feature',
  geometry: {
    type: 'LineString',
    coordinates: [[0.1278, 51.5074], [-74.0059, 40.7128]]
  }
});
```

Circle features can be generated using `geoCircle()`. This creates a circle generator which returns a GeoJSON object representing a circle.

Typically the center ( `[lon, lat]`) and the radius (in degrees) are set:

```js
let circleGenerator = geoCircle()
  .center([0.1278, 51.5074])
  .radius(5);

let circle = circleGenerator();
// returns a GeoJSON object representing a circle

geoGenerator(circle);
// returns a path string representing the projected circle
```

A GeoJSON grid of longitude and latitude lines (known as a graticule) can be generated using `graticule()`. This creates a graticule generator which returns a GeoJSON object representing the graticules:

```js
let graticuleGenerator = geoGraticule();

let graticules = graticuleGenerator();
// returns a GeoJSON object representing the graticule

geoGenerator(graticules);
// returns a path string representing the projected graticule
```

(See the [official documentation](https://github.com/d3/d3-geo#geoGraticule) for detailed information on graticule configuration.)

Here's an example where a line, a circle and graticules are added to a map:

### Spherical geometry [Anchor link for: spherical geometry](https://www.d3indepth.com/geographic/\#spherical-geometry)

There's a handful of D3 methods that may come in useful from time to time. The first of these `.geoArea()`, `.geoBounds()`, `.geoCentroid()`, `.geoDistance()` and `geoLength()` are similar to the path geometry methods described above but operate in spherical space.

#### Interpolation [Anchor link for: interpolation](https://www.d3indepth.com/geographic/\#interpolation)

The `geoInterpolate()` method creates a function that accepts input between 0 and 1 and interpolates between two `[lon, lat]` locations:

```js
let londonLonLat = [0.1278, 51.5074];
let newYorkLonLat = [-74.0059, 40.7128];
let geoInterpolator = geoInterpolate(londonLonLat, newYorkLonLat);

geoInterpolator(0);
// returns [0.1278, 51.5074]

geoInterpolator(0.5);
// returns [-41.182023242967695, 52.41428456719971] (halfway between the two locations)
```

#### geoContains [Anchor link for: geocontains](https://www.d3indepth.com/geographic/\#geocontains)

If you're using a `canvas` element to render your geometry you don't have the luxury of being able to add event handlers onto SVG `path` elements. Instead you can check whether mouse or touch events occur inside the boundary of a feature. You can do this using `geoContains` which accepts a GeoJSON feature and a `[lon, lat]` array and returns a boolean:

```js
geoContains(ukFeature, [0.1278, 51.5074]);
// returns true
```

Click an area to highlight

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Data Requests
# Requesting data with D3

Any time a web browser wishes to request a resource, be it an HTML file, a JPEG image or a CSV file, it uses an **HTTP request**.

> For the purposes of this chapter you don't need to understand HTTP requests in detail but if you wish to learn more I recommend [Codecademy's guide](https://www.codecademy.com/articles/http-requests).

Typically the data (or resource) you wish to request will have a **URL** (Uniform Resource Locator) such as `https://assets.codepen.io/2814973/my-csv.csv`.

> The URL can also be relative to the `index.html` of your web application so it might look like `data/my-csv.csv`

## D3 requests [Anchor link for: d3 requests](https://www.d3indepth.com/requests/\#d3-requests)

D3 makes requesting data relatively simple. It deals with the HTTP request and can also transform the incoming data into a useful format. For example it can request a CSV (comma separated value) file and transform it into an array of objects.

This chapter will focus on requesting common data formats namely CSV, TSV and JSON. When building data visualisations these are the only formats I use.

### Requesting CSV data [Anchor link for: requesting csv data](https://www.d3indepth.com/requests/\#requesting-csv-data)

CSV files are text files containing tabular data. For example:

```text
rank,workers,company,state_l,city,growth,revenue,industry
1,227,Fuhu,California,El Segundo,158956.9106,195640000,Consumer Products & Services
2,191,Quest Nutrition,California,El Segundo,57347.9246,82640563,Food & Beverage
3,145,Reliant Asset Management,Virginia,Arlington,55460.1646,85076502,Business Products & Services
4,62,Superfish,California,Palo Alto,26042.963,35293000,Software
5,92,Acacia Communications,Massachusetts,Maynard,20690.4578,77652360,Telecommunications
...
```

You typically export CSV files from spreadsheets and databases. Much of the open data you find on the web is also in CSV format.

Typically (but not always) the first line contains the names of each field ( `rank`, `workers`, `company` etc.). The remaining lines contain the data. Each value is separated by a comma.

You can use `csv` (from the `d3-fetch` module) to request a CSV file:

```js
csv('https://assets.codepen.io/2814973/Inc5000+Company+List_2014-top250.csv')
  .then(function(data) {
    console.log(data);
  });
```

`csv` accepts the URL as its first parameter and returns a **promise** object.

A promise object represents an **asynchronous** operation. An asynchronous operation is an operation whose result is some time in the future. This means that your code can continue to run immediately after initiating the request.

When the browser receives the requested data, the promise is **fulfilled** and the function that's passed into the promise's `.then` method is called.

> You don't need to fully understand promises to use `csv`. The main thing to remember is to pass a callback function into the `.then` method. The callback method is called when the file arrives. Its first parameter is the data.

When the request is fulfilled, D3 converts the incoming CSV file into an array of objects. Each object represents a row of data:

```json
[\
  {\
    "rank": "1",\
    "workers": "227",\
    "company": "Fuhu",\
    "state_l": "California",\
    "city": "El Segundo",\
    "growth": "158956.9106",\
    "revenue": "195640000",\
    "industry": "Consumer Products & Services"\
  },\
  {\
    "rank": "2",\
    "workers": "191",\
    "company": "Quest Nutrition",\
    "state_l": "California",\
    "city": "El Segundo",\
    "growth": "57347.9246",\
    "revenue": "82640563",\
    "industry": "Food & Beverage"\
  },\
  {\
    "rank": "3",\
    "workers": "145",\
    "company": "Reliant Asset Management",\
    "state_l": "Virginia",\
    "city": "Arlington",\
    "growth": "55460.1646",\
    "revenue": "85076502",\
    "industry": "Business Products & Services"\
  },\
  ...\
]
```

> `csv` assumes the first row contains field names.
>
> Note that all the numbers are represented by strings. We'll show how to convert these back to numbers later on.

The above array can be joined to HTML or SVG elements. For example:

```js
function update(data) {
  select('#content tbody')
    .selectAll('tr')
    .data(data)
    .join('tr')
    .html(function(d) {
      let html = '<tr>';
      html += '<td>' + d.company + '</td>';
      html += '<td>' + d.industry + '</td>';
      html += '<td>' + d.revenue + '</td>';
      html += '<td>' + d.workers + '</td>';
      html += '</tr>';
      return html;
    });
}

csv('https://assets.codepen.io/2814973/Inc5000+Company+List_2014-top250.csv')
  .then(function(data) {
    update(data);
  });
```

| Company | Sector | Revenue ($) | Number of workers |
| --- | --- | --- | --- |
| Fuhu | Consumer Products & Services | 195640000 | 227 |
| Quest Nutrition | Food & Beverage | 82640563 | 191 |
| Reliant Asset Management | Business Products & Services | 85076502 | 145 |
| Superfish | Software | 35293000 | 62 |
| Acacia Communications | Telecommunications | 77652360 | 92 |
| Provider Power | Energy | 137977203 | 50 |
| Crescendo Bioscience | Health | 27308000 | 129 |
| Plexus Worldwide | Health | 159897088 | 130 |
| Vacasa | Travel & Hospitality | 26263454 | 264 |
| Go Energies | Energy | 32851754 | 11 |
| Minute Key | Consumer Products & Services | 15782039 | 113 |
| Sainstore | Business Products & Services | 19243863 | 135 |
| The HCI Group | Health | 34583142 | 153 |
| Dynamic Dental Partners Group | Health | 19802935 | 313 |
| Aseptia | Food & Beverage | 13887650 | 159 |
| Asentra Health | Health | 20445071 | 34 |
| American Solar Direct | Energy | 52086567 | 436 |
| Prescient Edge | Government Services | 12315210 | 42 |
| BlueSquare Resolutions | Financial Services | 46400872 | 27 |
| BES Design/Build | Engineering | 11819161 | 44 |
| Simpler Trading | Financial Services | 11260000 | 12 |
| sweetFrog Premium Frozen Yogurt | Food & Beverage | 34382478 | 790 |
| Base Commerce | Financial Services | 12479598 | 17 |
| CPSG Partners | IT Services | 17095000 | 102 |
| MedHOK | Health | 17037000 | 102 |
| Showroom Logic | Advertising & Marketing | 13443409 | 90 |
| WeVeel | Consumer Products & Services | 9007000 | 27 |
| PackIt | Consumer Products & Services | 11874148 | 10 |
| American Retirement Advisors | Financial Services | 13876488 | 8 |
| HighPoint Global | Business Products & Services | 95810719 | 200 |
| AdKarma | Advertising & Marketing | 13326503 | 33 |
| Axtria | IT Services | 8963909 | 176 |
| Dolls Kill | Retail | 7585000 | 24 |
| Centric Digital | Business Products & Services | 18045419 | 140 |
| Retail Capital | Financial Services | 7013359 | 55 |
| Restore Health | Health | 6821205 | 61 |
| OpenRoad Lending | Financial Services | 8853881 | 53 |
| Pontchartrain Partners | Government Services | 10545091 | 25 |
| Team Extreme Marketing International | Consumer Products & Services | 6772856 | 1 |
| Choice Energy | Energy | 20894369 | 4 |
| ReviMedia | Advertising & Marketing | 5963105 | 24 |
| SmartZip Analytics | Software | 11396150 | 96 |
| Thompson Gray | Government Services | 14104761 | 48 |
| MCSG Technologies | IT Services | 7686703 | 147 |
| Innovative Surveillance Solutions | Security | 10247444 | 20 |
| Nordic | Health | 81410104 | 379 |
| Michigan Realty Solutions | Real Estate | 6178120 | 40 |
| Ohio Investments | Real Estate | 23809245 | 17 |
| Adore Me | Retail | 5637838 | 30 |
| IQ Formulations | Health | 8269660 | 35 |
| MAX Digital | Software | 6577541 | 32 |
| MaxHome | Construction | 5792929 | 50 |
| Alex and Ani | Retail | 230109687 | 1106 |
| Crowdtap | Advertising & Marketing | 6261593 | 46 |
| Compass Automation | Manufacturing | 5703235 | 30 |
| Multifamily Utility | Real Estate | 5757194 | 35 |
| The Joint | Health | 5958067 | 19 |
| Bizness Apps | Software | 6178728 | 70 |
| EcoSense Lighting | Manufacturing | 15363997 | 59 |
| PhotoBin | Consumer Products & Services | 6385268 | 61 |
| PMG Worldwide | Advertising & Marketing | 5764577 | 44 |
| Victor Securities | Financial Services | 6494832 | 19 |
| eLan Technologies | IT Services | 9149555 | 89 |
| Centennial Lending Group | Financial Services | 166889598 | 41 |
| Tough Mudder | Health | 107900476 | 143 |
| Netcom3 Global | Software | 30058088 | 40 |
| Gideon Services | Government Services | 23252268 | 3 |
| Viderity | Government Services | 18327000 | 34 |
| Affectiva | Software | 5017670 | 37 |
| AdHarmonics | Advertising & Marketing | 45929345 | 40 |
| Acordis International | IT Services | 6000834 | 28 |
| KRAVE Pure Foods | Food & Beverage | 16940863 | 40 |
| Main Street Hub | Advertising & Marketing | 9157664 | 175 |
| First Point Power | Energy | 23499000 | 4 |
| Ethology | Advertising & Marketing | 8815804 | 64 |
| Regal Wings | Travel & Hospitality | 54355000 | 126 |
| Solect Energy Development | Energy | 12477972 | 23 |
| Old Pro Roofing | Construction | 4897229 | 16 |
| Clean Energy Experts | Advertising & Marketing | 6058237 | 53 |
| LogoUp.com | Retail | 8003961 | 32 |
| ANALYTICA | IT Services | 15010399 | 28 |
| Phunware | Software | 22119065 | 131 |
| iCracked | Consumer Products & Services | 7315850 | 39 |
| BuyBackWorld | Consumer Products & Services | 4139786 | 13 |
| Tahzoo | Advertising & Marketing | 5693350 | 49 |
| Connexion Point | Health | 18286053 | 1250 |
| Meister Cook | Business Products & Services | 7707138 | 2 |
| TUNE | Advertising & Marketing | 18904275 | 150 |
| Constructure Management | Construction | 33167746 | 28 |
| Pendo Management Group | Real Estate | 8471671 | 14 |
| Gemini Consulting & Services | IT Services | 6469651 | 45 |
| Next Step Living | Energy | 58009000 | 764 |
| FastPay | Financial Services | 5061986 | 26 |
| Early Upgrade | Consumer Products & Services | 18068816 | 6 |
| Yochana IT Solutions | IT Services | 5637285 | 90 |
| American Care Partners | Health | 6580396 | 192 |
| Prepay Nation | Financial Services | 110914763 | 10 |
| PEG Bandwidth | Telecommunications | 32895443 | 115 |
| Global Energy Efficiency | Energy | 12860765 | 108 |
| LaunchPoint | Health | 12899943 | 72 |
| Equipatron | Retail | 5284863 | 7 |
| GovSmart | Computer Hardware | 25433653 | 12 |
| The Clymb | Retail | 64460000 | 90 |
| Alliance Health | Health | 85596581 | 380 |
| Inkling | Software | 8149000 | 100 |
| Patriot Group International | Government Services | 24073472 | 80 |
| Insureon | Insurance | 11844049 | 65 |
| RevLocal | Advertising & Marketing | 7268587 | 146 |
| Apex Fuels | Energy | 134567633 | 37 |
| Multicoreware | Software | 7686082 | 200 |
| MobileHelp | Health | 18661656 | 87 |
| Ataraxis | Human Resources | 40765844 | 12 |
| Fortress Gold Group | Financial Services | 9809304 | 15 |
| AdColony | Advertising & Marketing | 52783000 | 73 |
| Integral Ad Science | Advertising & Marketing | 23442470 | 87 |
| Technomax | IT Services | 4002379 | 18 |
| hCentive | Health | 26493445 | 458 |
| Intelligent Audit | Logistics & Transportation | 318842114 | 14 |
| SimpliSafe Home Security | Security | 38454825 | 60 |
| Boxman Studios | Business Products & Services | 4322910 | 43 |
| SeatGeek | Consumer Products & Services | 12274000 | 30 |
| Smashwords | Media | 22037828 | 23 |
| Securityhunter | Government Services | 35931650 | 18 |
| VRx | Health | 89554237 | 74 |
| SmackTom.com | Retail | 3125000 | 42 |
| Virtual Fleet Supervisor | Software | 3526101 | 10 |
| CareCloud | Health | 10455000 | 262 |
| Fueled | Advertising & Marketing | 6486000 | 64 |
| Bob's Watches | Retail | 11101120 | 14 |
| CPA Trend | Advertising & Marketing | 5826876 | 6 |
| Jobs2Careers | Human Resources | 22359716 | 17 |
| 29 Prime | Advertising & Marketing | 20289054 | 200 |
| Prolim | IT Services | 5129970 | 180 |
| Loyal Source Government Services | Government Services | 55980536 | 867 |
| Marketsmith | Advertising & Marketing | 72908666 | 24 |
| Project Management Academy | Education | 8094996 | 18 |
| Flying Cork Media | Advertising & Marketing | 7502709 | 25 |
| Motivity Labs | IT Services | 3225899 | 160 |
| Twilio | Telecommunications | 51720000 | 232 |
| Signature Closers | Real Estate | 3843580 | 20 |
| PureCars | Advertising & Marketing | 8725985 | 81 |
| The Cambridge Institute of International Education | Education | 9784000 | 96 |
| Market6 | Software | 15085838 | 53 |
| LiveRamp | Advertising & Marketing | 21040412 | 53 |
| MyClean | Consumer Products & Services | 4399793 | 160 |
| PresenceLearning | Education | 5906000 | 35 |
| Residential Capital Management | Real Estate | 30167124 | 140 |
| Total Technology Solutions Group | Business Products & Services | 3115496 | 14 |
| Buy PD | Real Estate | 79837059 | 98 |
| Goal Zero | Consumer Products & Services | 34249000 | 120 |
| Advocate Merchant Solutions | Financial Services | 4531348 | 89 |
| Sky Zone Indoor Trampoline Park | Consumer Products & Services | 88183962 | 2200 |
| Avenue Link | Advertising & Marketing | 6360103 | 11 |
| Incredible Supply & Logistics | Government Services | 7422000 | 12 |
| ReSell | Business Products & Services | 4728621 | 14 |
| Legion Logistics | Logistics & Transportation | 15115027 | 29 |
| GrayPay | Financial Services | 2981762 | 11 |
| Urban Investment Group | Real Estate | 4822398 | 1 |
| SPHERE Technology Solutions | Security | 3595000 | 12 |
| Bai Brands | Food & Beverage | 17139891 | 64 |
| RocketDrop | Business Products & Services | 72626345 | 15 |
| ECHO Health | Health | 46984261 | 24 |
| Marathon TS | Government Services | 6821409 | 75 |
| AudioMicro | Media | 5426086 | 8 |
| LED Supply | Business Products & Services | 2877743 | 6 |
| LeGault Homes | Real Estate | 7660396 | 6 |
| Forte International Tax | Financial Services | 3475711 | 9 |
| Paradigm Mechanical | Construction | 5250000 | 31 |
| Finance Store | Financial Services | 4590707 | 45 |
| Pure Incubation | Advertising & Marketing | 4696917 | 27 |
| Kohana Coffee | Food & Beverage | 2825786 | 10 |
| Ensighten | Advertising & Marketing | 8277000 | 107 |
| Pathway Genomics | Health | 14426053 | 123 |
| CenseoHealth | Health | 117230240 | 325 |
| 3A/WorldWide | Advertising & Marketing | 57568000 | 270 |
| 180Fusion | Advertising & Marketing | 6662008 | 90 |
| Kamis | IT Services | 3058705 | 47 |
| Apex Controls | Energy | 7789273 | 35 |
| InkSoft | Software | 2488706 | 16 |
| Futurewave Systems | IT Services | 2768000 | 19 |
| 6 Pack Fitness | Retail | 6310305 | 20 |
| Genzum Life Sciences | Health | 8561253 | 10 |
| ProctorU | Education | 6435816 | 247 |
| Dakenna Development | Construction | 8270918 | 19 |
| Duda | Software | 5532830 | 68 |
| Holganix | Environmental Services | 4306568 | 35 |
| NITS Solutions | IT Services | 2775411 | 15 |
| Paramount Lodging Advisors | Real Estate | 2465605 | 18 |
| EmazingLights | Retail | 5842010 | 35 |
| Level Interactive | Advertising & Marketing | 11958616 | 35 |
| shopkick | Retail | 26319118 | 75 |
| TekWissen | IT Services | 7802802 | 129 |
| VPCinnovations | Computer Hardware | 5390952 | 15 |
| Clean Energy Collective | Energy | 9453000 | 42 |
| Silver Bullet Construction | Construction | 2524000 | 13 |
| Aegis Corps | Government Services | 2900488 | 48 |
| uBreakiFix | Retail | 26472870 | 300 |
| Culture.Service.Growth. | Business Products & Services | 7993065 | 302 |
| CardCash.com | Consumer Products & Services | 55788000 | 72 |
| Protein Bar | Food & Beverage | 14211083 | 450 |
| Metis Solutions | Government Services | 8686766 | 45 |
| Title Boxing Club | Health | 34252000 | 17 |
| VETS Etc. | IT Services | 6480926 | 52 |
| LocalResponse | Advertising & Marketing | 9565336 | 32 |
| Tongal | Advertising & Marketing | 8417085 | 36 |
| Novisync Solutions | IT Services | 8517670 | 84 |
| Tax Guard | Financial Services | 4354787 | 40 |
| Nexgen Property Solutions | Financial Services | 5378001 | 12 |
| PerformTel | Business Products & Services | 2273616 | 120 |
| R.J. Allen & Associates | Construction | 26199465 | 25 |
| Splash and Dash for Dogs International | Consumer Products & Services | 2291195 | 6 |
| ePremium Insurance | Insurance | 3795474 | 17 |
| McAfee Institute | Education | 39571912 | 15 |
| IDsecurityonline.com | Security | 4898356 | 7 |
| Wren | Retail | 5154056 | 25 |
| Newmind Group | IT Services | 15469496 | 16 |
| Obsidian Analysis | Government Services | 9105768 | 43 |
| Universal Synaptics | Government Services | 2149259 | 10 |
| Global Commerce and Services | Government Services | 3521801 | 13 |
| Stoneside Blinds & Shades | Consumer Products & Services | 4893244 | 42 |
| Blue Star Tec | IT Services | 3869970 | 35 |
| Loqate | Software | 4464093 | 22 |
| PresPro | Construction | 3539958 | 155 |
| PcCareSupport | IT Services | 2364977 | 59 |
| AltaSource Group | IT Services | 7116722 | 42 |
| VDX | IT Services | 8910000 | 74 |
| Cloudbilt | Software | 4074453 | 30 |
| Strategi Consulting | IT Services | 3475505 | 14 |
| PPT Fiberglass | Manufacturing | 2500000 | 3 |
| X5 Networks | IT Services | 2114664 | 4 |
| Pathoras | Government Services | 9306999 | 74 |
| American Wireless | Telecommunications | 42522345 | 11 |
| SendGrid | Software | 28906069 | 174 |
| Laudan Properties | Real Estate | 10107299 | 28 |
| Streamline Solutions | Real Estate | 7955530 | 20 |
| Eau De Luxe | Retail | 2540031 | 7 |
| Levitate Media | Media | 2094293 | 16 |
| Avani Technology Solutions | IT Services | 7333811 | 80 |
| Expert Technical Solutions | IT Services | 3493139 | 19 |
| Motiv Power Systems | Energy | 2681071 | 25 |
| Allurez | Retail | 3681934 | 10 |
| Logical Paradigm | IT Services | 7642008 | 125 |
| LiveRail | Advertising & Marketing | 72731000 | 125 |
| Hydro Flask | Consumer Products & Services | 12684307 | 24 |
| Act-On Software | Software | 19378839 | 250 |
| Spartan Value Investors | Real Estate | 3370905 | 3 |
| GreenRope | Software | 2129330 | 16 |
| Lending Club | Financial Services | 98002000 | 385 |
| DrChrono | Health | 2863000 | 24 |
| Capstone (Sausalito CA) | Business Products & Services | 13719024 | 75 |

#### Row conversion [Anchor link for: row conversion](https://www.d3indepth.com/requests/\#row-conversion)

As pointed out previously, D3 interprets numbers in the CSV file as **strings**.

You can convert strings to numbers at any point in your code but I recommend doing the conversion straightaway. This can be done by passing a function into `csv` as the second argument. The function is called on each row of data and you return a new object with any appropriate transformations.

In this example we convert strings to numbers (where appropriate) and rename some of the variable names:

```js
function convertRow(d) {
  return {
    rank: parseInt(d.rank),
    workers: parseInt(d.workers),
    name: d.company,
    state: d.state_l,
    city: d.city,
    growth: parseFloat(d.growth),
    revenue: parseFloat(d.revenue),
    sector: d.industry
  }
}

csv('https://assets.codepen.io/2814973/Inc5000+Company+List_2014-top250.csv', convertRow)
  .then(function(data) {
    console.log(data);
  });
```

Now the array of data looks like:

```js
[\
  {\
    "rank": 1,\
    "workers": 227,\
    "name": "Fuhu",\
    "state": "California",\
    "city": "El Segundo",\
    "growth": 158956.9106,\
    "revenue": 195640000,\
    "sector": "Consumer Products & Services"\
  },\
  {\
    "rank": 2,\
    "workers": 191,\
    "name": "Quest Nutrition",\
    "state": "California",\
    "city": "El Segundo",\
    "growth": 57347.9246,\
    "revenue": 82640563,\
    "sector": "Food & Beverage"\
  },\
  {\
    "rank": 3,\
    "workers": 145,\
    "name": "Reliant Asset Management",\
    "state": "Virginia",\
    "city": "Arlington",\
    "growth": 55460.1646,\
    "revenue": 85076502,\
    "sector": "Business Products & Services"\
  },\
  ...\
]
```

### Requesting TSV data [Anchor link for: requesting tsv data](https://www.d3indepth.com/requests/\#requesting-tsv-data)

TSV data is **tab separated value** data and is treated in a similar manner to CSV. Use `tsv` from the `d3-fetch` module to load TSV data.

### Requesting JSON data [Anchor link for: requesting json data](https://www.d3indepth.com/requests/\#requesting-json-data)

JSON is a file format that closely mirrors JavaScript arrays and objects. It allows for nested structures which gives it an edge over tabular file formats. JSON is commonly used as a file format by APIs.

Here's an example of a JSON file that's located at `https://assets.codepen.io/2814973/my-json.json`:

```json
[\
  {\
    "name": "Paris",\
    "indicator1": 4030,\
    "indicator2": 13.45\
  },\
  {\
    "name": "Tokyo",\
    "indicator1": 3912,\
    "indicator2": 45.41\
  },\
  {\
    "name": "New York",\
    "indicator1": 19481,\
    "indicator2": 32.53\
  }\
]
```

You request a JSON file using `json` from the `d3-fetch` module:

```js
json('https://assets.codepen.io/2814973/my-json.json')
  .then(function(data) {
    console.log(data);
  });
```

When the JSON file arrives, D3 converts it into a JavaScript array or object:

```js
[\
  {\
    "name": "Paris",\
    "indicator1": 4030,\
    "indicator2": 13.45\
  },\
  {\
    "name": "Tokyo",\
    "indicator1": 3912,\
    "indicator2": 45.41\
  },\
  {\
    "name": "New York",\
    "indicator1": 19481,\
    "indicator2": 32.53\
  }\
]
```

In this example, the JSON file represents an array, so you can join it to HTML or SVG elements:

```js
function update(data) {
  select('#content tbody')
    .selectAll('tr')
    .data(data)
    .join('tr')
    .html(function(d) {
      let html = '<tr>';
      html += '<td>' + d.name + '</td>';
      html += '<td>' + d.indicator1 + '</td>';
      html += '<td>' + d.indicator2 + '</td>';
      html += '</tr>';
      return html;
    });
}

json('https://assets.codepen.io/2814973/my-json.json')
  .then(function(data) {
    update(data);
  });
```

| Name | Indicator 1 | Indicator 2 |
| --- | --- | --- |
| Paris | 4030 | 13.45 |
| Tokyo | 3912 | 45.41 |
| New York | 19481 | 32.53 |

> Unlike CSV data, JSON data isn't necessarily an array of objects so `json` doesn't support row conversion functions.

### Further notes [Anchor link for: further notes](https://www.d3indepth.com/requests/\#further-notes)

If the resource has a different domain (e.g. the `https://assets.codepen.io` part) to your web application, the server might not be willing to fulfil the request due to [CORS restrictions](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). However in this chapter we request files that are free from CORS restrictions.

Another thing to bear in mind is if you're developing your code locally (rather than on CodePen or similar) you need to have a local webserver running. If you're not sure how to do this I recommend reading [Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualization](https://leanpub.com/html-svg-css-js-for-data-visualisation/).

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Transitions Guide
# D3 Transitions

_D3 transitions let you smoothly **animate** between different **chart states**. This article shows how to add transitions to selection updates, how to set transition duration, how to create staggered transitions, how to change the easing function, how to chain transitions and how to create custom tween functions._

For example, let's [join](https://www.d3indepth.com/datajoins) an array of 5 numbers to SVG circles. When the 'Update data' button is clicked, the data is randomised and the circles jump to new positions:

Update data

If we add a transition to the circles the circles move smoothly to their new locations:

Update data

Furthermore, **entering circles** (circles that have just been created) and **exiting circles** (circles that are about to be removed) can be transitioned in specific ways. In this example new circles fade in and exiting circles drop down the page:

Update data

## How to create a D3 transition [Anchor link for: how to create a d3 transition](https://www.d3indepth.com/transitions/\#how-to-create-a-d3-transition)

Creating a basic transition using D3 is fairly straightforward. Suppose you have the following code which joins an array of random data to `circle` elements:

```js
let data = [];

function updateData() {
  data = [];
  for(let i=0; i<5; i++) {
    data.push(Math.random() * 800);
  }
}

function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cy', 50)
    .attr('r', 40)
    .attr('cx', function(d) {
      return d;
    });
}

function updateAll() {
  updateData();
  update();
}

updateAll();
```

> If you're not familiar with the above code I suggest reading the [data joins chapter](https://www.d3indepth.com/datajoins).

The `updateAll` function is called when a button is clicked:

```html
<button onClick="updateAll();">Update data</button>
```

`updateAll` calls `updateData` which randomises the `data` array. It also calls `update` which joins `data` to `circle` elements.

When the button is clicked the circles jump to new locations:

Update data

To use D3 transitions you must import the `d3-transition` module. This module adds transition methods to D3 selections and it only needs to be imported once in your project:

```js
import `d3-transition`;
```

You can then add a `.transition()` call before the `.attr` and `.style` methods that you wish to transition:

```js
function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cy', 50)
    .attr('r', 40)
    .transition()
    .attr('cx', function(d) {
      return d;
    });
}
```

In this example, the `.transition` call is followed by a single `.attr` call. This results in the `cx` attribute of the circles transitioning into new positions:

Update data

> The `.transition` method returns a 'transition selection'. This is basically the same as a normal D3 selection, except the `.attr` and `.style` methods animate attributes and style. A transition selection has additional methods such as `.tween` which we cover later.

Once the `.transition` method has been called, subsequent calls to `.attr` and `.style` will animate attributes and style, respectively.

For example, let's randomise the radius and colour of each circle:

```js
...

function random(x) {return Math.floor(Math.random() * x);}

function updateData() {
  data = [];
  for(let i=0; i<5; i++) {
    data.push({
      x: random(800),
      r: random(40),
      fill: rgb(random(255), random(255), random(255))
    });
  }
}

...
```

In the update function we update the radii and fills **after** the `.transition` call:

```js
function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cy', 50)
    .transition()
    .attr('cx', function(d) {
      return d.x;
    })
    .attr('r', function(d) {
      return d.r;
    })
    .style('fill', function(d) {
      return d.fill;
    });
}
```

Now when the data updates, the **position**, **radius** and **colour** of each circle transitions:

Update data

## Duration and delay [Anchor link for: duration and delay](https://www.d3indepth.com/transitions/\#duration-and-delay)

You can change the duration of a transition by calling `.duration` after the `.transition` call. The `.duration` method accepts an argument which specifies the duration in milliseconds:

```js
select('svg')
  .selectAll('circle')
  .data(data)
  .join('circle')
  .attr('cy', 50)
  .attr('r', 40)
  .transition()
  .duration(2000)
  .attr('cx', function(d) {
    return d;
  });
```

In this example we've set the duration to 2000 milliseconds:

Update data

You can also specify a delay before which the transition starts:

```js
...
  .transition()
  .delay(2000)
  .attr('cx', function(d) {
    return d;
  });
```

The delay is usually used to delay each element in the selection by a different amount. For example, you can create **staggered** transitions by passing a **function** into `.delay` and setting the delay to a multiple of the element index `i`:

```js
select('svg')
  .selectAll('circle')
  .data(data)
  .join('circle')
  .attr('cy', 50)
  .attr('r', 40)
  .transition()
  .delay(function(d, i) {
    return i * 75;
  })
  .attr('cx', function(d) {
    return d;
  });
```

Update data

## Easing functions [Anchor link for: easing functions](https://www.d3indepth.com/transitions/\#easing-functions)

An **easing function** defines the change in speed of an element during a transition. For example, some easing functions cause the element to start quickly and gradually slow down. Others do the opposite (start slowly and speed up) while others define special effects such as bouncing.

D3 has a number of easing functions defined in the `d3-ease` module which you can try out in this explorer:

easeBackeaseBackIneaseBackInOuteaseBackOuteaseBounceeaseBounceIneaseBounceInOuteaseBounceOuteaseCircleeaseCircleIneaseCircleInOuteaseCircleOuteaseCubiceaseCubicIneaseCubicInOuteaseCubicOuteaseElasticeaseElasticIneaseElasticInOuteaseElasticOuteaseExpeaseExpIneaseExpInOuteaseExpOuteaseLineareasePolyeasePolyIneasePolyInOuteasePolyOuteaseQuadeaseQuadIneaseQuadInOuteaseQuadOuteaseSineaseSinIneaseSinInOuteaseSinOutUpdate data

> In general 'in' refers to the start of the motion and 'out' refers to the end of the motion. Therefore, `easeBounceOut` causes the element to bounce at the **end** of the transition. `easeBounceInOut` causes the element to bounce at the **start and end** of the transition.

> It's usually better to use easings where the element moves quickly at first and slows down. For example `easeCubicOut` is a commonly used easing function where the element moves quickly at first and slows down. D3's default easing function is `easeCubic` which is equivalent to `easeCubicInOut`. This causes the element to start slowly, accelerate, then finish slowly.

To use easing import an easing function from `d3-ease` and pass it into the `.ease` method:

```js
select('svg')
  .selectAll('circle')
  .data(data)
  .join('circle')
  .attr('cy', 50)
  .attr('r', 40)
  .transition()
  .ease(easeBounceOut)
  .attr('cx', function(d) {
    return d;
  });
```

Update data

## Chained transitions [Anchor link for: chained transitions](https://www.d3indepth.com/transitions/\#chained-transitions)

Transitions can be chained together by adding multiple calls to `.transition`. Each transition takes it in turn to proceed. (When the first transition ends, the second one will start, and so on.)

For example, let's chain two transitions. The first sets the `cx` attribute and the second sets the `r` attribute (and uses `easeBounce`):

```js
function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cy', 50)
    .transition()
    .attr('cx', function(d) {
      return d.x;
    })
    .transition()
    .duration(750)
    .ease(easeBounce)
    .attr('r', function(d) {
      return d.r;
    });
}
```

When the chart updates, the circles move to their new positions, then the radius changes (with a bounce):

Update data

## Custom tweens [Anchor link for: custom tweens](https://www.d3indepth.com/transitions/\#custom-tweens)

In most circumstances D3 is able to transition attributes and style in a sensible manner. However there are times where the default behaviour might not be suitable.

For example, suppose we join an array of angle values to `circle` elements. Each circle is placed on the circumference of a larger circle using the joined value to determine where on the circle it sits. An angle of zero corresponds to 3 o'clock on the large circle.

When the data updates, the circles travel in a straight line:

Update data

You can customise the path the elements take (such as along the circumference of the large circle) by using a **tween function**.

To use a tween function, call the `.tween` function at some point after `.transition`. You pass a name (which can be anything you like) and a function into `.tween`.

The function gets called once for each element in the selection. It must return a **tween function** which will get called at each step of the transition. A time value `t` between 0 and 1 is passed into the tween function. ( `t` is 0 at the beginning of the transition and 1 at the end.)

```js
select('svg g')
  .selectAll('circle')
  .data(data)
  .join('circle')
  .transition()
  .tween('my-tween', function(d) {
    ...

    // Return a tween function
    return function(t) {
      // Do stuff here such as updating your HTML/SVG elements
    }
  });
```

Typically you'll set up **interpolator function(s)** in the outer function. An interpolator function takes a parameter between 0 and 1 and interpolates between two given values. The interpolator function can be used when updating HTML/SVG elements in the tween function.

For example:

```js
let data = [], majorRadius = 100;

function updateData() {
  data = [Math.random() * 2 * Math.PI];
}

function getCurrentAngle(el) {
  // Compute the current angle from the current values of cx and cy
  let x = select(el).attr('cx');
  let y = select(el).attr('cy');
  return Math.atan2(y, x);
}

function update() {
  select('svg g')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('r', 7)
    .transition()
    .tween('circumference', function(d) {
      let currentAngle = getCurrentAngle(this);
      let targetAngle = d;

      // Create an interpolator function
      let i = interpolate(currentAngle, targetAngle);

      return function(t) {
        let angle = i(t);

        select(this)
          .attr('cx', majorRadius * Math.cos(angle))
          .attr('cy', majorRadius * Math.sin(angle));
      };
    });
}
```

In the function that's passed into `.tween` we start by computing `currentAngle`.

We then set up an **interpolator function** `i`. This is a function that interpolates between two values ( `currentAngle` and `targetAngle` in our case). The function `i` accepts a number between `0` and `1` and interpolates between the two values. `interpolate` is imported from `d3-interpolate`.

Next we create a tween function and return it. The tween function uses the interpolator function `i` to compute `angle` for the given time value `t`. It then updates the `cx` and `cy` attributes using `angle`. The tween function is called for each step of the transition.

Now when the button is clicked, the circle moves along the circumference of the large circle. Notice also that when the button is rapidly clicked, the transition starts from the circle's current (mid-transition) position:

Update data

## Entering and exiting elements [Anchor link for: entering and exiting elements](https://www.d3indepth.com/transitions/\#entering-and-exiting-elements)

You can define specific transitions for **entering** and **exiting** elements. (Entering elements are newly created elements and exiting elements are ones that are about to be removed.)

For example you might want entering circles to **fade in** and exiting circles to **fall**:

Update data

To define enter and exit transitions you need to pass **three functions** into the `.join` method. This was covered in the [Enter, exit and update](https://www.d3indepth.com/enterexit) chapter so if you're not familiar with these concepts I suggest you read up on them there.

As a brief reminder, you can pass three functions (instead of an element name) into the `.join` method:

```js
.join(
  function(enter) {
    ...
  },
  function(update) {
    ...
  },
  function(exit) {
    ...
  }
)
```

The first, second and third functions are named the **enter**, **update** and **exit** functions, respectively.

### Entering elements [Anchor link for: entering elements](https://www.d3indepth.com/transitions/\#entering-elements)

As covered in [Enter, exit and update](https://www.d3indepth.com/enterexit) chapter the enter function should append an element to each element of the enter selection.

You can also **set the style and attributes** of entering elements and this has the effect of **initialising** elements before any transitions take place.

Let's initialise `cy`, `cx`, `r` and `opacity` on entering circles:

```js
.join(
  function(enter) {
    return enter
      .append('circle')
      .attr('cy', 50)
      .attr('cx', function(d) {
        return d;
      })
      .attr('r', 40)
      .style('opacity', 0);
  },
  function(update) {
    return update;
  },
  function(exit) {
    return exit.remove();
  }
)
```

The initial x and y coordinates of entering circles are initialised so that the circles appear in place (rather than sliding in from the origin).

The initial radius of entering circles is initialised so that the circles appear with a radius of 40.

Finally the opacity of entering circles is initialised to 0 so that entering circles fade in. (We set the final opacity later on.)

### Exiting elements [Anchor link for: exiting elements](https://www.d3indepth.com/transitions/\#exiting-elements)

The exit function usually removes the elements in the exit selection:

```js
.join(
  ...
  function(exit) {
    return exit.remove();
  }
)
```

> If you don't call `.remove` on the exit selection, the elements will remain on the page.

You can add a transition to exiting elements by calling `.transition` on the exit selection. For example, to make exiting elements fall off the page, use `.transition` and set the `cy` attribute to a large value:

```js
.join(
  function(enter) { ... },
  function(update) { ... },
  function(exit) {
    return exit
      .transition()
      .attr('cy', 500)
      .remove();
  }
)
```

The `.remove` method of a transition selection removes the selection's element(s) when the transition ends.

### Updating elements [Anchor link for: updating elements](https://www.d3indepth.com/transitions/\#updating-elements)

You can apply a transition to entering and updating elements by adding a call to `.transition` after the `.join` call. This will cause all elements (except exiting elements) to transition.

Let's add a `.transition` call and set the `cx` attribute and the `opacity`:

```js
select('svg')
  .selectAll('circle')
  .data(data)
  .join(
    function(enter) { ... },
    function(update) { ... },
    function(exit) { ... }
  )
  .transition()
  .attr('cx', function(d) {
    return d;
  })
  .style('opacity', 0.75);
```

This has the following effect:

- when the data changes, the circles transition to new positions (because of `.attr('cx')`)
- when new circles are created, they fade in

The circles fade in because their initial opacity is set to zero in the enter function and the `.style` call animates the opacity to 0.75.

### Putting it all together [Anchor link for: putting it all together](https://www.d3indepth.com/transitions/\#putting-it-all-together)

Here's the complete example where:

- circles fade in (without sliding or expanding)
- circles transition to new positions
- circles fall off the page when they exit

```js
select('svg')
  .selectAll('circle')
  .data(data)
  .join(
    function(enter) {
      return enter
        .append('circle')
        .attr('cy', 50)
        .attr('cx', function(d) { return d; })
        .attr('r', 40)
        .style('opacity', 0);
    },
    function(update) {
      return update;
    },
    function(exit) {
      return exit
        .transition()
        .attr('cy', 500)
        .remove();
    }
  )
  .transition()
  .attr('cx', function(d) { return d; })
  .style('opacity', 0.75);
```

Update data

To summarise:

- entering elements are initialised in the **enter function**. This is first function passed into `.join`. This allows you to initialise style and attributes of entering elements (before the transition starts)
- a transition is applied to exiting elements in the **exit function**. This is the third function passed into `.join`.
- entering and existing elements are transitioned by adding a call to `.transition` after `.join`

> The update function (the second argument of `.join`) only updates existing elements (and not entering elements) and I rarely add any special code here.

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Interaction Techniques
# Picking, Dragging and Brushing with D3

D3 provides a number of modules that help you add interactivity such as zooming, panning and brushing.

In this chapter we cover:

- **quadtree** (to make picking small items easier)
- **dragging** (for moving elements)
- **brushing** (for selecting regions)

Zoom and pan are covered in a [separate section](https://www.d3indepth.com/zoom-and-pan).

## Quadtrees [Anchor link for: quadtrees](https://www.d3indepth.com/interaction/\#quadtrees)

If your chart contains items sized according to a data variable (such as a bubble chart) hovering over (or clicking) tiny items can be difficult.

Try hovering over the tiny circles:

You can make picking small items easier by searching for the closest item to the mouse pointer each time the mouse is moved. This can be an expensive operation but can be made more efficient using D3's **quadtree** module.

> A quadtree is a tree data structure that recursively divides an area into smaller and smaller areas and can make searching for items more efficient.

With D3's quadtree function (from the `d3-quadtree` module) you can create a quadtree, add some points to it, then find the closest point to a given coordinate.

Create a quadtree by calling `quadtree()` then add points to it using `.add`:

```js
let quadtree = quadtree();

quadtree.add([50, 100]);
quadtree.add([100, 100]);
```

In the above example two points have been added: `50, 100` and `100, 100`.

Given a coodinate `x, y` you can find the nearest point in the quadtree using `.find(x, y)`:

```js
quadtree.find(55, 105); // returns [50, 100]
quadtree.find(90, 95); // returns [100, 100]
```

You can also add a distance (as the third argument) so that only points within that distance are returned:

```js
quadtree.find(60, 100, 20); // returns [50, 100]
quadtree.find(60, 100, 5); // returns undefined
```

The first `.find` returns `[50, 100]` because this is the closest point and is within a distance of `20`. The second `.find` returns `undefined` because the closest point `[50, 100]` is more than 5 away. This is useful for ensuring the returned point is close to the requested point. Without this constraint, outlier points can get selected even though the pointer isn't very close.

You can add an array of points using `.addAll`:

```js
quadtree.addAll([[10, 50], [60, 30], [80, 20]]);
```

> The `.add` and `.addAll` methods are cumulative i.e. the existing quadtree points persist.

If you've an array of objects, you can specify accessor functions using the `.x` and `.y` methods:

```js
let data = [\
  { x: 50, y: 100 },\
  { x: 100, y: 100 }\
];

let quadtree = quadtree()
  .x(function(d) {return d.x;})
  .y(function(d) {return d.y;});

quadtree.addAll(data);

quadtree.find(60, 100); // returns {x: 50, y: 100}
```

### Example [Anchor link for: example](https://www.d3indepth.com/interaction/\#example)

Let's look at an example where we create some randomised points ( `updateData`) and add them to a quadtree ( `updateQuadtree`). We draw the points ( `update`) and set up a `mousemove` event on the `svg` element ( `initEvents`).

When the mouse moves (see `handleMousemove`) we search for the nearest point to the mouse pointer using the quadtree. We update `hoveredId` with the found point's id then call `update` again so that the hovered point is coloured red:

```js
let data = [], width = 600, height = 400, numPoints = 100;

let quadtree = quadtree()
  .x(function(d) {return d.x;})
  .y(function(d) {return d.y;});

let hoveredId;

function updateData() {
  data = [];
  for(let i=0; i<numPoints; i++) {
    data.push({
      id: i,
      x: Math.random() * width,
      y: Math.random() * height,
      r: 1 + Math.random() * 20
    });
  }
}

function handleMousemove(e) {
  let pos = pointer(e, this);
  let d = quadtree.find(pos[0], pos[1], 20);
  hoveredId = d ? d.id : undefined;
  update();
}

function initEvents() {
  select('svg')
    .on('mousemove', handleMousemove);
}

function updateQuadtree() {
  quadtree.addAll(data);
}

function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; })
    .attr('r', function(d) { return d.r; })
    .style('fill', function(d) { return d.id === hoveredId ? 'red' : null;});
}

updateData();
updateQuadtree();
update();
initEvents();
```

> In `handleMousemove` we use `pointer` which given the event object `e` and an HTML/SVG element, returns the mouse position relative to the HTML/SVG element. In our example, `this` is the `SVG` element because this is the element `.on` was called on (see `initEvents`). `pointer` is imported from the `d3-selection` module.

Now your mouse pointer only needs to be within 20 pixels of its nearest circle:

> D3's quadtree is also used by [`forceCollide`](https://www.d3indepth.com/force-layout/#forcecollide) when detecting collisions in the force layout.

\\n\\n

\\n \\n \\n

\\n","css":"circle {\\n\\topacity: 0.5;\\n}\\n","js":"// For bundlers such as Vite and Webpack omit https://esm.sh/\\nimport { select, pointer } from 'https://esm.sh/d3-selection';\\nimport { quadtree } from 'https://esm.sh/d3-quadtree';\\n\\nlet data = \[\], width = 600, height = 400, numPoints = 100;\\nlet triangles;\\nlet hoveredId;\\n\\nfunction updateData() {\\n\\tdata = \[\];\\n\\tfor(let i=0; i

-->

## Dragging [Anchor link for: dragging](https://www.d3indepth.com/interaction/\#dragging)

D3 has a module `d3-drag` for adding drag behaviour to elements. Dragging is where you hover over an element, press the mouse button, move the pointer, then release the mouse button, in order to move the element. D3's drag module also supports touch gestures.

There's three steps to making HTML/SVG elements draggable:

- call `drag()` to create a **drag behaviour** function
- add an event handler that's called when a drag event occurs. The event handler receives an event object with which you can update the position of the dragged element
- attach the drag behaviour to the elements you want to make draggable

Calling `drag()` creates a drag behaviour:

```js
let drag = drag();
```

> A drag behaviour is a function that adds event listeners to elements. It also has methods such as `.on` defined on it.

You can attach an event handler to the drag behaviour by calling the `.on` method. This accepts two arguments:

- the event type ( `'drag'`, `'start'` or `'end'`)
- the name of your event handler function

```js
function handleDrag(e) {
 // update the dragged element with its new position
}

let drag = drag()
  .on('drag', handleDrag);
```

> The event types are `'drag'`, `'start'` and `'end'`. `'drag'` indicates a drag. `'start'` indicates the start of the drag (e.g. the user has pressed the mouse button). `'end'` indicates the end of the drag (e.g. the user has released the mouse button).

`handleDrag` receives a single parameter `e` which is an object representing the drag event. The drag event object has several properties, the most useful of which are:

| Property name | Description |
| --- | --- |
| `.subject` | The joined data of the dragged element (or a [fallback object](https://github.com/d3/d3-drag/tree/v3.0.0#drag_subject)) |
| `.x` & `.y` | The new coordinates of the dragged element |
| `.dx` & `.dy` | The new coordinates of the dragged element, relative to the previous coordinates |

> You can see a full list of drag event properties in the [official documentation](https://github.com/d3/d3-drag/tree/v3.0.0#drag-events).

If the dragged element was created by a [data join](https://www.d3indepth.com/datajoins) and the joined data has `x` and `y` properties, the `x` and `y` properties of the drag event object are computed such that the **relative position of the element and pointer are maintained**. (This prevents the element's center 'snapping' to the pointer position.) Otherwise `x` and `y` are the pointer position **relative to the dragged element's parent element**.

You attach the drag behaviour to elements by selecting the elements and passing the drag behaviour into the [`.call` method](https://www.d3indepth.com/selections/#call).

For example to add drag behaviour to `circle` elements:

```js
select('svg')
  .selectAll('circle')
  .call(drag);
```

> The drag behaviour is a function that sets up event listeners on the selected elements (each `circle` element in the above example). When drag events occur the event handler ( `handleDrag` in the above examples) is called.

### Example [Anchor link for: example 1](https://www.d3indepth.com/interaction/\#example-1)

In the following code an array of random coordinates is joined to `circle` elements ( `updateData` and `update`).

A drag behaviour is created using `drag()` and attached to the `circle` elements ( `initDrag`).

When a circle is dragged, `handleDrag` gets called and an event object `e` is passed in as the first argument. `e.subject` represents the joined data of the dragged element. The `x` and `y` properties of the joined data are updated to `e.x` and `e.y`. `update` is then called to update the circle positions.

```js
let data = [], width = 600, height = 400, numPoints = 10;

let drag = drag()
  .on('drag', handleDrag);

function handleDrag(e) {
  e.subject.x = e.x;
  e.subject.y = e.y;
  update();
}

function initDrag() {
  select('svg')
    .selectAll('circle')
    .call(drag);
}

function updateData() {
  data = [];
  for(let i=0; i<numPoints; i++) {
    data.push({
      id: i,
      x: Math.random() * width,
      y: Math.random() * height
    });
  }
}

function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; })
    .attr('r', 40);
}

updateData();
update();
initDrag();
```

Notice that the relative position of the pointer and dragged circle is maintained (try initiating a drag near the edge of a circle):

## Brushing [Anchor link for: brushing](https://www.d3indepth.com/interaction/\#brushing)

Brushing lets you user **specify an area** (by pressing the mouse button, moving the mouse, then releasing) in order to, for example, select a group of elements.

Try selecting circles by pressing the mouse button, dragging, then releasing the button:

D3 has a module `d3-brush` for adding brushing behaviour to an element (or, less commonly, multiple elements).

There's three steps to adding brush behaviour to an HTML or SVG element:

- call `brush()` to create a **brush behaviour** function
- add an event handler that's called when a brush event occurs. The event handler receives the brush extent which can then be used to select elements, define a zoom area etc.
- attach the brush behaviour to an element (or elements)

Calling `brush()` creates a brush behaviour:

```js
let brush = brush();
```

> A brush behaviour is a function that has methods such as `.on` defined on it. The function itself adds event listeners to an element as well as additional elements (mainly `rect` elements) for rendering the brush extent.

You can attach an event handler to a brush behaviour by calling the `.on` method. This accepts two arguments:

- the event type ( `'brush'`, `'start'` or `'end'`)
- the name of your event handler function

```js
function handleBrush(e) {
 // get the brush extent and use it to, for example, select elements
}

let brush = brush()
  .on('brush', handleBrush);
```

> The event types are `'brush'`, `'start'` and `'end'`. `'brush'` indicates that the brush extent has changed. `'start'` indicates the brushing has started (e.g. the user has pressed the mouse button). `'end'` indicates the end of brushing (e.g. the user has released the mouse button).

`handleBrush` receives a single parameter `e` which is an object representing the brush event. The most useful property on the brush event is `.selection` which represents the extent of the brush as an array `[[x0, y0], [x1, y1]]` where `x0, y0` and `x1, y1` are the opposite corners of the brush. Typically `handleBrush` will compute which elements are within the brush extent and update them accordingly.

You attach the brush behaviour to an element by selecting the element and passing the brush behaviour into the [`.call` method](https://www.d3indepth.com/selections/#call):

```js
select('svg')
  .call(brush);
```

### Examples [Anchor link for: examples](https://www.d3indepth.com/interaction/\#examples)

#### Basic example [Anchor link for: basic example](https://www.d3indepth.com/interaction/\#basic-example)

In the following example a brush is created using `brush()`. An event handler `handleBrush` is added to the brush behaviour using the `.on` method.

`handleBrush` gets called whenever brushing starts (the `'start'` event type) or the brush extent changes (the `'brush'` event type).

The brush behaviour is attached to the `svg` element by calling `.call` and passing in the brush behaviour (see `initBrush`).

```js
let brush = brush()
  .on('start brush', handleBrush);

function handleBrush(e) {
  // Use the brush extent e.selection to compute, for example, which elements to select
}

function initBrush() {
  select('svg')
    .call(brush);
}

initBrush();
```

#### Full example [Anchor link for: full example](https://www.d3indepth.com/interaction/\#full-example)

Here's a complete example where an array of random coordinates is joined to `circle` elements ( `updateData` and `update`). When the brush is active, the circles within the brush extent are coloured red.

The brush is initialised in `initBrush`. (Note that it's attached to a `g` element within the `svg` element, in order to keep the elements used to render the brush separate to the circles.)

When brushing occurs, `handleBrush` is called. This receives a brush event object `e` which has a property `selection` that defines the extent of the brush. This is saved to the variable `brushExtent` and `update` is called.

`update` performs the data join and colours circles red if they're within the extent defined by `brushExtent` (see `isInBrushExtent`):

```js
let data = [], width = 600, height = 400, numPoints = 100;

let brush = brush()
  .on('start brush', handleBrush);

let brushExtent;

function handleBrush(e) {
  brushExtent = e.selection;
  update();
}

function initBrush() {
  select('svg g')
    .call(brush);
}

function updateData() {
  data = [];
  for(let i=0; i<numPoints; i++) {
    data.push({
      id: i,
      x: Math.random() * width,
      y: Math.random() * height
    });
  }
}

function isInBrushExtent(d) {
  return brushExtent &&
    d.x >= brushExtent[0][0] &&
    d.x <= brushExtent[1][0] &&
    d.y >= brushExtent[0][1] &&
    d.y <= brushExtent[1][1];
}

function update() {
  select('svg')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; })
    .attr('r', 4)
    .style('fill', function(d) {
      return isInBrushExtent(d) ? 'red' : null;
    });
}

initBrush();
updateData();
update();
```

### One dimensional brushes [Anchor link for: one dimensional brushes](https://www.d3indepth.com/interaction/\#one-dimensional-brushes)

D3 also provides brushes `brushX` and `brushY` that constrain the brush to a single dimension.

They work in a simlar fashion to `brush`, the main difference being the event object's `.selection` property which is an array of two numbers `[min, max]` which represent the extent of the brush.

Here's an example using `brushX`:

### Programmatic control of brushing [Anchor link for: programmatic control of brushing](https://www.d3indepth.com/interaction/\#programmatic-control-of-brushing)

You can also set the brush extent programmatically. For example you can create a button that sets the brush to maximum size.

The brush behaviour has two methods for setting the brush extent `.move` and `.clear`. The first sets the brush extent to `[[x0, y0], [x1, y1]]` and the second clears the brush.

`.move` and `.clear` should be called on the element that receives the brush gestures. For example:

```js
select('svg g')
  .call(brush.move, [[50, 50], [100, 100]]);
```

Here's an example that has two buttons. One button sets the brush extent to the size of the `svg` element and the other button clears the brush:

Select allClear selection

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3 Zoom and Pan
# D3 Zoom and Pan

D3 provides a module `d3-zoom` that adds **zoom** and **pan** behaviour to an HTML or SVG element. This page shows how to create zoom behaviours, how to add zoom and pan constraints and how to zoom and pan programmatically.

In the following example, click and move the mouse to pan and use the mouse wheel to zoom. Touch gestures should also work:

When zoom and pan gestures (such as dragging or a pinch gesture) occur, a transform (consisting of scale and translate) is computed by D3 and passed into an event handler. The event handler typically applies the transform to chart elements.

There's three steps to add zoom and pan behaviour to an element:

- call `zoom()` to create a **zoom behaviour** function
- add an event handler that gets called when a zoom or pan event occurs. The event handler receives a transform which can be applied to chart elements
- attach the zoom behaviour to an element that receives the zoom and pan gestures

It's helpful to distinguish between the HTML or SVG element that **receives the zoom and pan gestures** and the elements that **get zoomed and panned** (the elements that get transformed). It's important that these elements are different, otherwise the panning won't work properly.

Calling `zoom()` creates a zoom behaviour:

```js
let zoom = zoom();
```

> Although it's called `zoom`, this module handles zoom **and** pan events.

> A zoom behaviour is a function that adds event handlers (for drags, mouse wheel events and touch events etc.) to an element. It also has methods such as `.on` defined on it.

You can attach an event handler to your zoom behaviour by calling the `.on` method. This accepts two arguments:

- the event type ( `'zoom'`, `'start'` or `'end'`)
- the name of your event handler function

```js
function handleZoom(e) {
 // apply transform to the chart
}

let zoom = zoom()
  .on('zoom', handleZoom);
```

> The event types are `'zoom'`, `'start'` and `'end'`. `'zoom'` indicates a change of transform (e.g. the user has zoomed or panned). `'start'` indicates the start of the zoom or pan (e.g. the user has pressed the mouse button). `'end'` indicates the end of the zoom or pan (e.g. the user has released the mouse button).

`handleZoom` receives a single parameter `e` which is an object representing the zoom event. The most useful property on this object is `transform`. This is an object that represents the latest zoom transform and is typically applied to the chart element(s):

```js
function handleZoom(e) {
  select('g.chart')
    .attr('transform', e.transform);
}
```

> `e.transform` has three properties `x`, `y` and `k`. `x` and `y` specify the translate transform and `k` represents the scale factor. It also has a `.toString` method which generates a string such as `"translate(38.9,-4.1) scale(1.3)"`. This means you can pass `e.transform` directly into `.attr`.

You attach the zoom behaviour to an element by selecting the element and passing the zoom behaviour into the [`.call` method](https://www.d3indepth.com/selections/#call):

```js
select('svg')
  .call(zoom);
```

> The zoom behaviour is a function that sets up event listeners on the selected element ( `svg` in the above example). When zoom and pan events occur, a transform is computed and passed into the event handler ( `handleZoom` in the above examples).

### Example [Anchor link for: example](https://www.d3indepth.com/zoom-and-pan/\#example)

Suppose you have an SVG element that contains a `g` element:

```html
<svg width="600" height="400">
  <g></g>
</svg>
```

In the following code a zoom behaviour is created using `zoom()` and attached to the `svg` element.

`handleZoom` is passed into the `.on` method. When a zoom or pan occurs, `handleZoom` gets called. This applies the transform `e.transform` to the `g` element.

```js
function handleZoom(e) {
  select('svg g')
    .attr('transform', e.transform);
}

let zoom = zoom()
  .on('zoom', handleZoom);

select('svg')
  .call(zoom);
```

Here's a full example where an array of random coordinates is joined to `circle` elements:

```js
let data = [], width = 600, height = 400, numPoints = 100;

let zoom = zoom()
  .on('zoom', handleZoom);

function handleZoom(e) {
  select('svg g')
    .attr('transform', e.transform);
}

function initZoom() {
  select('svg')
    .call(zoom);
}

function updateData() {
  data = [];
  for(let i=0; i<numPoints; i++) {
    data.push({
      id: i,
      x: Math.random() * width,
      y: Math.random() * height
  	});
  }
}

function update() {
  select('svg g')
    .selectAll('circle')
    .data(data)
    .join('circle')
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; })
    .attr('r', 3);
}

initZoom();
updateData();
update();
```

Use the mouse wheel and dragging, or touch gestures, to zoom and pan the circles:

### Zoom and pan constraints [Anchor link for: zoom and pan constraints](https://www.d3indepth.com/zoom-and-pan/\#zoom-and-pan-constraints)

You can constrain the zoom and pan so that the user can only zoom and pan within specified bounds.

The zoom can be constrained using `.scaleExtent` into which you pass an array `[min, max]` where `min` is the minimum scale factor and `max` is the maximum scale factor:

```js
let zoom = zoom()
  .scaleExtent([1, 5]);
```

You can use `.translateExtent` to specify bounds `[[x0, y0], [x1, y1]]` that the user can't pan outside of:

```js
let width = 600, height = 400;

let zoom = zoom()
  .scaleExtent([1, 5])
  .translateExtent([[0, 0], [width, height]]);
```

Now you can only zoom in up to a scale factor of 5. Neither can you zoom out beyond the default scale factor of 1. In addition you cannot pan beyond the bounds of the chart:

### Programmatic zoom control [Anchor link for: programmatic zoom control](https://www.d3indepth.com/zoom-and-pan/\#programmatic-zoom-control)

You can also zoom and pan programmatically. For example you can create buttons that zoom the chart when clicked.

The zoom behaviour has the following methods for setting the zoom and pan programmatically:

| Method name | Description |
| --- | --- |
| `.translateBy` | adds a given `x, y` offset to the current transform |
| `.translateTo` | sets the transform such that a given `x, y` coordinate is centered (or positioned on a given point `[px, py]`) |
| `.scaleBy` | multiplies the current scale factor by a given value |
| `.scaleTo` | sets the scale factor to a given value |
| `.transform` | sets the transform to a given transform. (Use [`zoomIdentity`](https://github.com/d3/d3-zoom/tree/v3.0.0#zoom-transforms) to create a zoom transform.) |

The above methods shouldn't be called directly. Instead, they should be called on the element that receives the zoom and pan gestures. For example:

```js
select('svg')
  .call(zoom.scaleBy, 0.5);
```

You can also call these methods on a transition selection, which results in nice effects:

```js
select('svg')
  .transition()
  .call(zoom.translateBy, 50, 0);
```

Here's a full example using a few of the above methods:

Zoom inZoom outReset zoomPan leftPan rightCenter

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## Creating D3 Chart Axes
# D3 Axes

_How to create chart axes using D3's axis module. This article covers axis orientation, transitions, number of ticks, custom tick values, tick formatting and tick size._

One of the most useful D3 modules (especially when creating bar, line and scatter charts) is the **axis module** which draws axes:

0102030405060708090100

## How to create an axis [Anchor link for: how to create an axis](https://www.d3indepth.com/axes/\#how-to-create-an-axis)

You need two things to create a D3 axis:

- an SVG element to contain the axis (usually a `g` element)
- a D3 [scale function](https://www.d3indepth.com/scales)

A D3 scale function has a domain and range (see the [scales](https://www.d3indepth.com/scales) chapter). The domain specifies the input extent (for example `[0, 100]`) and the range defines the output extent (for example `[0, 1000]`) of the scale.

When a D3 scale function is used to define an axis, the scale domain determines the minimum and maximum tick values and the range determines the length of the axis.

To create an axis:

- make an axis generator function using `axisBottom`, `axisTop`, `axisLeft` or `axisRight` (and pass in your scale function)
- select the container element and pass the axis generator into `.call`

The axis functions are imported from `d3-axis`. For example:

```js
import { axisBottom } from 'd3-axis';
```

Here's a basic example:

```html
<svg width="600" height="100">
  <g transform="translate(20, 50)"></g>
</svg>
```

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale);

select('svg g')
  .call(axis);
```

0102030405060708090100

> We cover `.call` in the [selections](https://www.d3indepth.com/selections) chapter. In brief you pass a function into `.call`. The function's first parameter is a selection with which the function can operate on. An axis generator (the `axis` variable in the above example) appends `path`, `line` and `text` elements (that represent the axis) to the selection.

> The axis can be positioned by transforming the axis's container. In the above example, the `g` element that contains the axis is translated by `(20, 50)`.

### Axis orientation [Anchor link for: axis orientation](https://www.d3indepth.com/axes/\#axis-orientation)

`axisBottom`, `axisTop`, `axisLeft` and `axisRight` are used to generate axes that are suitable for the bottom, top, left and right of a chart, respectively:

```html
<svg width="500" height="500">
  <g id="left" transform="translate(30, 40)"></g>
  <g id="right" transform="translate(450, 40)"></g>
  <g id="top" transform="translate(40, 30)"></g>
  <g id="bottom" transform="translate(40, 450)"></g>
</svg>
```

```js
let scale = scaleLinear().domain([0, 100]).range([0, 400]);

let axisLeft = axisLeft(scale);
let axisRight = axisRight(scale);
let axisTop = axisTop(scale);
let axisBottom = axisBottom(scale);

select('#left').call(axisLeft);
select('#right').call(axisRight);
select('#top').call(axisTop);
select('#bottom').call(axisBottom);
```

0102030405060708090100010203040506070809010001020304050607080901000102030405060708090100

### Scale types [Anchor link for: scale types](https://www.d3indepth.com/axes/\#scale-types)

You can pass in any scale function that has numeric output. This includes `scaleLinear`, `scaleSqrt`, `scaleLog`, `scaleTime`, `scaleBand` and `scalePoint`.

Here's an example using each scale type:

scaleLinear0102030405060708090100scaleSqrt0102030405060708090100scaleLog10203040501002003004005001kscaleTime2020FebruaryMarchAprilMayJunescaleBandMonTueWedThuFriscalePointMonTueWedThuFri

> `scaleBand` is useful for bar charts. Read more [here](https://www.d3indepth.com/scales/#scaleband).

### Transitions [Anchor link for: transitions](https://www.d3indepth.com/axes/\#transitions)

If the scale's domain changes, the axis can be updated by calling `.call(axis)` again:

```js
select('svg g')
  .call(axis);
```

You can also add a call to `.transition` to make the axis animate:

```js
select('svg g')
  .transition()
  .call(axis);
```

0102030405060708090100

Change scale domain

## Axis configuration [Anchor link for: axis configuration](https://www.d3indepth.com/axes/\#axis-configuration)

You can configure axes in the following ways:

- specify the number of ticks OR specify the tick values
- specify the format of the tick label (for example, add a percentage sign)
- specify the tick size

### Number of ticks [Anchor link for: number of ticks](https://www.d3indepth.com/axes/\#number-of-ticks)

You can use the `.ticks` method to specify how many ticks the axis has:

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale);

axis.ticks(20);

select('svg g')
  .call(axis);
```

05101520253035404550556065707580859095100

> D3 tries to use as many ticks as requested, but in some cases it'll use more or less in order for the tick values to be round numbers.

> The axis uses its scale function's `.ticks` method to generate an array of tick values.

### Tick values [Anchor link for: tick values](https://www.d3indepth.com/axes/\#tick-values)

You can specify the axis's tick values by passing an array of tick values into the `.tickValues` method:

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale);

axis.tickValues([0, 25, 50, 75, 100]);

select('svg g')
  .call(axis);
```

0255075100

### Tick label formatting [Anchor link for: tick label formatting](https://www.d3indepth.com/axes/\#tick-label-formatting)

You can format the tick label in two ways.

The first is to use the `.ticks` method and pass in a format string as the second argument:

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale);

axis.ticks(4, "$.2f");

select('svg g')
  .call(axis);
```

$0.00$20.00$40.00$60.00$80.00$100.00

> We've already seen that the first argument of `.ticks` is the number of ticks. You can pass in `null` if you want to use the default number of ticks.

The format string is powerful and is described in depth in the [d3-format section of the official documentation](https://github.com/d3/d3-format#locale_format).

The second approach is to pass a formatting function into the `.tickFormat` method. The function accepts a value and outputs a formatted value.

In this example we add a % symbol to each tick value:

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale);

axis.ticks(4)
  .tickFormat(function(d) {
    return d + "%";
  });

select('svg g')
  .call(axis);
```

0%20%40%60%80%100%

### Tick size [Anchor link for: tick size](https://www.d3indepth.com/axes/\#tick-size)

The length of the ticks can be set using the `.tickSize` method. You can also set the distance between the tick and the tick label using `.tickPadding`:

```js
let scale = scaleLinear().domain([0, 100]).range([0, 500]);

let axis = axisBottom(scale)
  .tickPadding(10)
  .tickSize(10);

select('svg g')
	.call(axis);
```

0102030405060708090100

The axis is made up of a `path` element (that looks like a long square bracket and represents two end ticks and the main axis line) and `line` elements that represent each tick (including the end ticks).

You can set the length of the end ticks of the `path` element using `.tickSizeOuter` and the length of the `line` elements using `.tickSizeInner`. (I'm not sure of when this might be used.)

You can also create grid lines by setting the tick size to your chart width (or height). In this example we use `axisLeft` and set the tick size to 500. The axis also has a transform of `translate(520, 20)` and it's `path` element that represents the main axis is hidden. (If the main axis was visible, you'd see it to the right of the grid lines.)

0102030405060708090100

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## Data Visualization Resources
BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## D3.js Circle Transitions
Update data

## Easing Functions Overview
Update data

## D3.js Transitions
Update data

## D3 Data Visualisation Guide
# About

D3 in Depth aims to bridge the gap between introductory tutorials/books and the [official documentation](https://github.com/d3/d3/blob/master/API.md). It's written by [Peter Cook](https://peterrcook.com/) who worked as a freelance data visualisation designer/maker before joining [Flourish](https://flourish.studio/) as a senior visualisation developer.

This guide assumes that you're reasonably proficient in HTML, SVG and JavaScript. If not, I recommend reading my book [Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualisation](https://leanpub.com/html-svg-css-js-for-data-visualisation/).

D3 in Depth was started in 2016 and currently covers versions 6 and 7 of D3. There are some important differences between versions 6, 5, 4 and 3 and I'll mention them as appropriate.

If you're interested in learning how to build a beautiful, custom data visualisation from scratch using D3 I recommend reading [D3 Start to Finish](https://leanpub.com/d3-start-to-finish/). You'll learn about:

- requesting CSV data using D3
- D3 data joins (including joining nested data)
- architecting a data visualisation using a layout function
- detailed styling using CSS
- adding a popup using Flourish's popup library
- state management
- animations using D3 transitions
- data manipulation using Lodash
- adding a menu, legend and footer

and more.

Be sure to visit [Create With Data](https://createwithdata.com/) for more articles and tutorials on making data visualisations.

If you've any comments or questions please tweet [@d3indepth](https://twitter.com/d3indepth) or email info@d3indepth.com.

I hope you find this guide useful!

Peter

BOOKS & COURSES

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/data-dashboards-with-js.jpg)](https://leanpub.com/data-dashboards-with-javascript)

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

[Find out more](https://leanpub.com/data-dashboards-with-javascript)

[![](https://www.d3indepth.com/img/d3-start-to-finish.png)](https://www.createwithdata.com/d3-start-to-finish-book/)

_"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."_

[Javier García Fernández](https://jgf92.github.io/personal-page/)

Learn how to make a custom data visualisation using D3.js.

[Find out more](https://www.createwithdata.com/d3-start-to-finish-book/)

[![D3 Start to Finish book cover](https://www.d3indepth.com/img/visualising-data-with-js.jpg)](https://leanpub.com/visualising-data-with-javascript)

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

[Find out more](https://leanpub.com/visualising-data-with-javascript)

[![](https://www.d3indepth.com/img/fundamentals.jpg)](https://leanpub.com/html-svg-css-js-for-data-visualisation)

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

[Find out more](https://leanpub.com/html-svg-css-js-for-data-visualisation)

## Film Genre Hierarchies
Sony PicturesWalt Disney PicturesWarner Bros.ComedyActionDramaComedyAdventureDramaAdventure1121221

## Axis Long Ticks Examples
0102030405060708090100

## Axis Number Ticks
05101520253035404550556065707580859095100

## Axis Orientation Examples
0102030405060708090100010203040506070809010001020304050607080901000102030405060708090100

## Axis Tick Formatting
0%20%40%60%80%100%

## Axis Tick Size
0102030405060708090100

## D3 Axis Tick Values
0255075100

## D3 Axis Ticks
$0.00$20.00$40.00$60.00$80.00$100.00

## D3.js Axis Transitions
0102030405060708090100

Change scale domain

## Data Visualization Axes
0102030405060708090100

## Data Visualization Scales
scaleLinear0102030405060708090100scaleSqrt0102030405060708090100scaleLog10203040501002003004005001kscaleTime2020FebruaryMarchAprilMayJunescaleBandMonTueWedThuFriscalePointMonTueWedThuFri

## D3.js Data Joins
Update

## D3.js Data Joins
Z

Insert element

## D3.js Data Joins
LondonNew YorkSydneyParisBeijing

## D3.js Data Joins
Update

## D3 Data Joins
Z

Insert element

## Force-Directed Graphs
ABCDEFGH

## Highlight Geographic Areas
Click an area to highlight

## Geospatial Data Exploration
Hover over a country

## Map Projection Configurations
AzimuthalEqualAreaAzimuthalEquidistantGnomonicOrthographicStereographicAlbersConicConformalConicEqualAreaConicEquidistantEquirectangularMercatorTransverseMercator

scale (120)

0400

center (lon) (0)

-180180

center (lat) (0)

-9090

translate (x) (480)

0960

translate (y) (250)

0500

rotate (λ) (0)

-180180

rotate (φ) (0)

-180180

rotate (γ) (0)

-180180

## D3 Geographic Projections
# D3 core projections

Here are the 12 [core geographic projections](https://github.com/d3/d3-geo/blob/master/README.md#projections) in [D3](https://d3js.org/) (version 4.2). Equal radius circles are drawn to highlight area distortion (e.g. see Mercator).

From [D3 in Depth](http://d3indepth.com/).

## Interactive Data Visualization
Select allClear selection

## Data Visualization Tools
Zoom inZoom outReset zoomPan leftPan rightCenter

## D3.js Transition Techniques
Do transition

