Author avatar

Douglas Starnes

Fundamentals of D3.js

Douglas Starnes

  • Apr 9, 2020
  • 9 Min read
  • 3,148 Views
  • Apr 9, 2020
  • 9 Min read
  • 3,148 Views
Data
Data Analytics
Data Visualization
D3

Fundamentals of D3.js

One of the hottest topics in software development and engineering is data science and analytics. Even if you don't crunch the numbers yourself, your function in developing web apps will likely be impacted if it has not been already. A skill that you, as a front end web developer, might be expected to provide is designing visualizations. And no, I am not trying to convert you into a graphic designer. This guide will introduce D3, a JavaScript library for creating visualizations in the browser.

Setting Up a Development Environment

For the sake of convenience, this guide uses an online development environment, CodeSandbox. CodeSandbox is free to use, requiring only a Github account to log in. Links to the sandboxes are included for each example in the guide so that you can clone and experiment with them without installing anything.

D3 and the Document Object Model

If you've done front end web development, you know how important the Document Object Model (DOM) is. In D3, the DOM also has an important role. The primary object, D3, is named d3. It's kind of like the dollar sign in jQuery. The d3 object has a select method that accepts a string CSS selector. So if you had this HTML:

1<div id="green">I am green</div>
html

The following D3 statement would select it.

1d3.select('div#green').style('color', 'green');
js

Notice that you are able to call the style method on the return value of select, which is a reference to the element that matched the selector. This chaining behavior is again similar to jQuery.

Here is the result:

Imgur

And the link to the live example on CodeSandbox

Working with SVG

But D3 is for creating graphics in visualizations! Another web standard you may be familiar with, SVG or Scalable Vector Graphics, adds the ability to create graphic objects in the browser. Like the DOM, SVG also has an object model. D3 depends on SVG to create graphics in visualizations. The action all takes place inside of an svg tag:

1<svg height="480" width="640" />
html

This simply creates a container for SVG graphics with dimensions of 640 by 480 pixels. The real power comes when this is selected with D3. You can then begin to add basic shapes, such as a circle:

1d3.select('svg')
2  .append('circle');
js

This won't show the circle because it has no coordinates or radius. These attributes are chained with the attr method:

1d3.select('svg')
2  .append('circle')
3  .attr('cx', 320)
4  .attr('cy', 240)
5  .attr('r', 100)
6  .attr('fill', red)
js

This code will place the circle in the center of the svg element, give it a radius of 100 pixels, and fill it with red. It will generate SVG code similar to:

1<circle cx="320" cy="240" r="100" fill="red" />
html

Here is the result:

Imgur

And the link to the live example on CodeSandbox

Loading JSON Data

This is where things start to get interesting. Many times, the purpose of a visualization is to tell the story of data. D3 has a flexible and powerful mechanism for loading and working with data in several formats. This example will use JSON. In the sandbox, you'll find a sales.json file in the data directory. Here is a snippet:

1[
2  {
3    "conference_name": "Joy of JavaScript",
4    "tickets_sold": 100,
5    "tickets_available": 150
6  }
7...
8]
json

This data is from my frequently recycled demo app, Conference Barrel, which is a conference management app. The sales.json file contains data about conference ticket sales. To load this data into D3, use the json method:

1d3.json('../data/sales.json');
js

There are also other methods for other file types such as CSV.

This code returns a promise object so you can chain the then method and access the data:

1d3.json('../data/sales.json')
2  .then(data => {
3    data.forEach((el, idx) => document.body.appendChild(generate_div(el.conference_name)));
4  });
js

The data variable is the JSON object parsed from the sales.json file. Since it is an array, you can iterate over it with the forEach method and display the names of the conferences in the page.

Here is the result:

Imgur

And the link to the live example on CodeSandbox

Data Binding

This is where the rubber meets the road. You know how to work with the DOM, how to use SVG, and how to load data. It's time to put it all together and make a visualization. This example will be a simple bar chart showing ticket sales for each conference. The bars will be SVG rect elements. Each rect will have attributes for the x and y position, height, and width, as well as a fill color. The code for that will be similar to the circle element you saw before. The trick is getting the rect to represent the data. Here is the code:

1d3.json('../data/sales.json')
2  .then(data => {
3    var svg = d3.select('svg');
4    svg
5      .selectAll('rect')
6      .data(data)
7      .enter()
8      .append('rect');
js

This may look a little strange but it's a common idiom with D3. You've seen everything up until the selectAll method. This will do what the name suggests and select any existing rect elements in the SVG container. In this case there are none, so it will return an empty collection. If there had been existing rect elements, they would have been associated with the values in the data when the data method is called. Any leftover values in data would be passed to enter which calls append once for each value. But since there are no rect elements, this is the same as calling append once for each value in data.

But again, just like with circle you have to add the attributes to display any graphics. Since this is a bar chart, the width of the rect will be proportional to the tickets_sold key in the data. To get this value, pass a function instead of a value as the second argument to attr. It will accept the current value from the data and an index of that value. Get the tickets_sold key and use it for the width. The y coordinate will be based off of the index. Create the rest of the bar chart with this code:

1d3.json('../data/sales.json')
2  .then(data => {
3    // omitted
4    .append('rect')
5    .attr('x', 0)
6    .attr('y', (val, idx) => idx * BAR_SPACING)
7    .attr('width', (val, idx) => val.tickets_sold)
8    .attr('height', BAR_HEIGHT)
9    .attr('fill', green);
js

Here is what D3 displays:

Imgur

And the link to the live example on CodeSandbox

Adding Text

Even though visualizations are supposed to be graphical representations of data, a few numbers for emphasis don't hurt. Text is easy to add using D3. The text will go in text elements that are added just like the rect elements were:

1d3.json("../data/sales.json").then(data => {
2  d3.select("svg")
3    .selectAll("text")
4    .data(data)
5    .enter()
6    .append("text")
7    .attr("x", 0)
8    .attr("y", (val, idx) => idx * BAR_SPACING + BAR_HEIGHT + TEXT_OFFSET)
9    .attr("color", "black")
10    .attr("font-size", "18px")
11    .text((val, idx) => `${val.conference_name} - ${val.tickets_sold}`);
12});
js

The new text method will set the text of the element. Like the attr method, it accepts a function with the data value and index.

Here is the result:

Imgur

And the link to the live example on CodeSandbox

The Final Visualization

You have learned all you need to create a visualization like this:

Imgur

And the link to the live example on CodeSandbox

There is only one new part of the code. But now there are two sets of rect elements and two sets of text. To prevent the previous rect and text from being selected, add a dummy class to each of the new ones that don't exist when making the call to selectAll.

Adding the red bars representing the unsold tickets is just another rect element, the width of which is the difference between the tickets_sold and tickets_available keys in the data. The y coordinate of the bar is offset by the width of the green bar, which is tickets_sold. The text in the bars is positioned 25 pixels from the right side, and the percentages don't involve D3 at all.

Conclusion

As you can see, in very little time you can create a useful visualization. But it doesn't stop here--D3 can create 3D visualizations and animations after you get a hold of the fundamentals. Check out the documentation at <d3js.org> for the details. Once again, remember that you can clone the sandboxes embedded in the guide and create your own visualizations with them. Thanks for reading this guide!