# 2d density chart

A 2D density chart is a graphical representation of data that uses color to show the concentration of data points in a given area. It shows the combined distribution of two quantitative variables. 2D density charts are often used in statistical analysis and data mining to identify trends, patterns, and correlations in the data.

In this tutorial, we will use the d3.js and React libraries to build a 2D density chart. It starts by describing how the data should be organized and how to initialize the `Density2d` component. It then explains how to prepare the data and compute bins. Once this is done, it shows how to render the shapes and suggests a few variations. 🙇‍♂️.

## The Data

A 2d density chart is basically a variation of the scatterplot, useful when the amount of data points is huge. As a result, it shares the same data structure.

The data is an array of object. For each object, at least 2 properties are required: `x` and `y`. The value of `x` is the position of the datapoint on the horizontal axis. The value of `y` is linked with the vertical axis.

``````const data = [
{
x: 2,
y: 4
},
{
x: 8,
y: 5
}
]``````

Two dimensional density charts are useful with big datasets. Switch to a scatterplot if you have few data points!

Scatterplot section

## Component skeleton

The goal here is to create a `Density2d` component that will be stored in a `Density2d.tsx` file. This component requires 3 props to render: a `width`, a `height`, and some `data`.

The shape of the `data` is described above. The `width` and `height` will be used to render an `svg` element in the DOM, in which we will insert the histogram.

To put it in a nutshell, that's the skeleton of our `Density2d` component:

``````import * as d3 from "d3"; // we will need d3.js

type Density2dProps = {
width: number;
height: number;
data: number[];
};

export const Density2d = ({ width, height, data }: Density2dProps) => {

// build the scales
// use the hexbin plugin to compute hexagons from the dataset
// draw the hexagons

return (
<div>
<svg width={width} height={height}>
// render all the hexagons
</svg>
</div>
);
};``````

It's fundamental to understand that with this code organization, d3.js will be used to prepare the SVG `circle`, but it's React that will render them in the `return()` statement. We won't use d3 methods like `append` that you can find in usual d3.js examples.

## Scales and axes

Scales and axes are computed and rendered exactly as for a scatterplot or a bubble chart. Please refer to the according sections.

Scales and axes is a recurring topic in data visualization. I plan to write complete articles on the topic. You can know when it's ready by subscribing to the project.

How to build a bottom axis and a left axis component using React, used to render a d3 scale.

## Compute hexagons with the `d3-hexbin` library

We have a set of points distributed on a 2d coordinate space. We want to split this space in hexagons, and compute the number of points in each hexagon.

Fortunately, the d3-hexbin library has everything we need to do so. This lib is not part of the main d3 bundle, install it with:

``npm install d3-hexbin``

### → The hexagon generator

The `d3-hexbin` plugin comes with a `hexbin()` function that returns a hexagon generator. This hexagon generator is a function. You give it some data, it computes the hexagons.

``````const hexbinGenerator = hexbin()
.radius(BIN_SIZE) // hexagon size in px
.extent([
[0, 0],
[boundsWidth, boundsHeight],
]);``````

Two arguments are passed to the `hexbin()` function:

• `radius` is the size of each hexagon
• `extent` is an array providing the x and y limits of our chart

### → Hexagon format

The `hexagonGenerator` expects some `data` as input. The data must be an array where each item provides the `x` and `y` coordinates of a data point in the 2d space.

You can provide this data using the following code:

``````const hexbinData = hexbinGenerator(
data.map((item) => [xScale(item.x), yScale(item.y)])
);``````

The result is an array of arrays. Each item represents a hexagon. Each hexagon is composed of all the values assigned to this hexagon. So its `length` is useful to compute the hexagon color.

Each bin has two additional attributes: `x` and `y` being the coordinates of the hexagon on the 2d space.

``````[
[[1,1], [1,2], [2,2], x: 1.5, y: 1.5],
[[12,14], [11,16], [9,12], x: 12, y: 12],
...
]``````

Let's draw those hexagons 🙇‍♂️!

## Drawing the hexagons

Finally! ✨

We can now `map` through the `hexbinData` array and draw a hexagon per item.

Fortunately, the `hexbinGenerator` built above comes with a `hexagon()` method that builds the shape of a hexagon for us. It's thus a breeze to render it in a `path` svg element:

``````const allShapes = hexbinData.map((d, i) => {
return (
<path
key={i}
d={hexbinGenerator.hexagon()}
transform={"translate(" + d.x + "," + d.y + ")"}
fill={colorScale(d.length)}
...
/>
);
});``````

Note that `transform` is used to translate a hexagon to its correct position.

A hexbin density chart built with d3.js and React.

## Responsive 2D Density with react

The component above is not responsive. It expects 2 props called `width` and `height` and will render a 2D Density of those dimensions.

Making the 2D Density responsive requires adding a wrapper component that gets the dimension of the parent `div`, and listening to a potential dimension change. This is possible thanks to a hook called `useDimensions` that will do the job for us.

`useDimensions`: a hook to make your viz responsive
``````export const useDimensions = (targetRef: React.RefObject<HTMLDivElement>) => {

const getDimensions = () => {
return {
width: targetRef.current ? targetRef.current.offsetWidth : 0,
height: targetRef.current ? targetRef.current.offsetHeight : 0
};
};

const [dimensions, setDimensions] = useState(getDimensions);

const handleResize = () => {
setDimensions(getDimensions());
};

useEffect(() => {
return () => window.removeEventListener("resize", handleResize);
}, []);

useLayoutEffect(() => {
handleResize();
}, []);

return dimensions;
}``````

I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.

## 2D Density inspiration

If you're looking for inspiration to create your next 2D Density, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!

dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your 2D Density looks good!

visit

## Variations

The hexbin representation above is just one member of a family of graphics allowing to study the combined distribution of two quantitative variables. You can read more about the existing variations in the data to viz project.

To put it in a nutshell, 2d histogram, Gaussian KDE, 2d density and Contour charts are the most common variations. It is of course possible to build them all using `react` and `d3.js`.

Here is an example with a contounr chart based on the same dataset than the previous example.

Contour chart made with React and D3.js.

ToDomake the contour chart above looks better
ToDoadd examples for 2d histograms and other variations
ToDoAdd example with a zoom feature implemented

## Contact

👋 Hey, I'm Yan and I'm currently working on this project!

Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting `yan.holtz.data` with `gmail.com`. You can also subscribe to the newsletter to know when I publish more content!