Search

Create data-driven documents with D3.js

Garry Smith

5 min read

Feb 13, 2015

Create data-driven documents with D3.js

If your data needs to portray a message and be easily understood, a visualization can really help you get your point across. Enter D3.js. This JavaScript framework is not new, but it is pretty shiny, and helps you present data in a consumable and understandable format by binding data to the Document Object Model (DOM).

With D3, there are countless possibilities. For example, D3 can help you chart your business’s quarterly financial results, visualize the relationships between species of salamanders or make a nifty music frequency visualizer.

Getting Started with D3.js

If you’re like me, you’ll take a look at the some of the more involved examples and your eyes will gloss over with awe and initimidation. Don’t sweat it. Like everything else, you should start with an introduction. Today we will be creating a simple bar chart.

First, create your index.html file.

	<!DOCTYPE html>
	<html>
	  <head>
	    <meta charset="utf-8" />
	    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	    <title>Big Nerd Ranch D3 Introduction</title>
	    <link rel="stylesheet" href="application.css" />
	  </head>

	  <body>
	    <div id="graph"></div>
	    <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
	    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
	    <script src="app.js"></script>
	  </body>
	</html>

Note: We will be using CDNs for jQuery and d3 but if you plan on working offline, make sure to download the libs to your project folder.

Next, create the app.js file in the same directory.

	$(document).ready(function () {

	});

Creating the SVG

Enough with the setup—let’s start writing some code. You can use DIVs to create your graphs, but we’re going to be using an SVG (Scalable Vector Graphic) and appending <rect> (rectangle) elements to it. First, lets create a little helper function in our app.js file to create the SVG.

	$(document).ready(function () {

		var svgHeight = 100;
		var svgWidth = 600;
		var barPadding = 1;

		function createSvg(parent, height, width) {
			return d3.select(parent)
					 .append('svg')
					 .attr('height', height)
					 .attr('width', width);
		}

		var graph = createSvg('#graph', svgHeight, svgWidth);

	});

The svgHeight and svgWidth variables will be the height and width of our SVG in pixels. The createSvg function accepts a parent DOM element selector that the SVG will be appended to (in our case, the <div id="graph"></div> element), along with its height and width. The d3.select(parent) will tell the D3 framework to select a DOM element to be acted upon. If you’re familiar with jQuery or CSS selectors, this is primarily the same thing. You can pass select() an ID or class name with the appropriate pretext, or simply any HTML element such as d3.select('body'). Once D3 selects that element, it returns a reference to that element which allows us to modify that element by chaining methods, in this case appending an SVG and setting attributes.

So step-by-step, our createSvg() method first selects the parent element we passed to it, then creates a new SVG element and appends it within the parent, then sets the height and width attributes of the new SVG element. Finally, since the last method in the chain .attr() is referencing the SVG element, the return statement in createSVG() is returning a reference to the SVG element. Pulling everything together, var graph = createSvg('#graph', svgHeight, svgWidth); creates the SVG and then stores the reference to the SVG element in the graph variable.

Building a Graph

Before we create our bar graph, we need some data to bind to it. D3 accepts many different formats of data, including JSON, GeoJSON and even CSV files, but for this intro, we will just be using a JavaScript array of numbers.

Add the following variable to your app.js:

var dataset = [12, 19, 8, 17, 22, 9, 15, 12, 22, 25, 17, 12, 25, 16];

Now let’s create the bars in our bar graph.

	graph.selectAll('rect')
	   .data(dataset)
	   .enter()
	   .append('rect')
	   .attr('width', svgWidth / dataset.length - barPadding)
	   .attr('height', function (d) {
	   		return d * 4;
	   })
	   .attr('x', function (d, i) {
	   		return i * (svgWidth / dataset.length);
	   })
	   .attr('y', function (d) {
	   		return svgHeight - (d * 4); // Align the bars to the bottom of the SVG.
	   });

d3 Introduction Bar Chart

Boom. You now have a bar graph worthy of visualizing team synergy at your next board meeting.

Let’s break down what this code snippet is doing.

	graph.selectAll('rect')
	   .data(dataset)
	   .enter()
	   .append('rect')

graph is referencing our SVG variable that we created earlier, and selectAll('rect') is saying, “Please find all the elements within our SVG.” Since there are currently none, D3 will prepare an empty array of element references.

Next, the .data(dataset) method binds our array of numbers to those references. Third, .enter() tells D3 to look at the data and create element references based on that data. Since there are 14 numbers in our dataset, D3 will create 14 element references.

Finally, .append('rect') appends those new elements to the DOM.

Without setting the height, width, and X and Y values, the SVG will look blank even though there are elements inside of it.

Since the .attr() methods are modifying an array of DOM references on the method chain, they will be invoked for each item in the array. This means you can gain access to each item’s value in the array by using an anonymous function. Let’s take a look at the last four methods:

	.attr('width', svgWidth / dataset.length - barPadding)
	.attr('height', function (d) {
		return d * 4;
	})
	.attr('x', function (d, i) {
		return i * (svgWidth / dataset.length);
	})
	.attr('y', function (d) {
		return svgHeight - (d * 4); // Align the bars to the bottom of the SVG.
	});

Laying it All out

The width of each bar in the graph is being set to a relative value based on how many items are in the array and the width of the SVG, so that the bar graph will take up the full width of the SVG. The height is using an anonymous function to gain access to the item’s value d and multiplying it by four, just to make the bars a little easier to see.

The X coordinate value is each bar’s position left-to-right on the SVG. We can gain access to each bar’s index in the array by adding a parameter i to the anonymous function. We want to space out the bars evenly, so set the X coordinate to be i * (svgWidth / dataset.length). The Y coordinate is a little different, since SVG rects use the top left corner as the point of origin, which is a little weird. If we didn’t provide a value for the Y coordinate, our bars would be upside down. That’s why we have to set the Y value to be the difference between the heights of the SVG and our bar.

Our example here was simple, but you can do a lot of cool things with D3! Go check out their examples and start building.

Mark Dalrymple

Reviewer Big Nerd Ranch

MarkD is a long-time Unix and Mac developer, having worked at AOL, Google, and several start-ups over the years.  He’s the author of Advanced Mac OS X Programming: The Big Nerd Ranch Guide, over 100 blog posts for Big Nerd Ranch, and an occasional speaker at conferences. Believing in the power of community, he’s a co-founder of CocoaHeads, an international Mac and iPhone meetup, and runs the Pittsburgh PA chapter. In his spare time, he plays orchestral and swing band music.

Speak with a Nerd

Schedule a call today! Our team of Nerds are ready to help

Let's Talk

Related Posts

We are ready to discuss your needs.

Not applicable? Click here to schedule a call.

Stay in Touch WITH Big Nerd Ranch News