September 1, 2016

Practical data visualization concepts in D3.js

By João Samouco | 7 min read

practical-data-visualization-concepts-in-d3

If you’ve ever used Microsoft Excel to visualize data into charts and graphs, you’ve probably also encountered some frustration with popular spreadsheet software. The strategic use of accessible data visualization is not only common sense but also provides a significant competitive advantage. There are entire startups dedicated to building Web Applications that create compelling visual representations based off metrics and various KPI’s. Big data isn’t only valuable to accountants and C-Level executives. Metrics can provide insight into a company’s performance but they really shine when you add a layer of interactivity as you visualize your data. Thanks to Mike Bostock, developers now have an Open Source option for crafting Excel-like data visualizations. We can use D3.js for manipulating documents based on our data and visualizing that same data using SVG’s, HTML and CSS.

At the core of D3 we have a framework that allow us to associate any object or array of data with elements on a page, binding them together for further manipulation. Update data and we visually update the object tied to that data within our document, in real time. We can use any number of visualizations to interpret data, display it as a graph, a chart, an eye catching animated SVG, or as patterns and gradients. These are just the most common examples. Once the data and the object are linked, the possibilities of visualizing them are endless. We’ll cover D3.js version 3, but it has since been updated to 4.0.

Basics

The D3 API needs us to designate a container that will house our visualization. Every element created within D3 must be created within a container otherwise it doesn’t exist. This is typically an SVG but D3 supports HTML and Canvas as well. D3.js can be boiled down to the following formula when binding data to an SVG visualization:

var dataset = [
    6, 10, 23, 46, 26, 64, 36, 59, 12, 31, 15, 40,
    64, 70, 67, 71, 64, 75, 33, 45];

var svg = d3.select(‘div.myElement’)
    .append('svg')
    .attr(‘width’, ‘300 px’)
    .attr(‘height’, ‘300 px’);

The svg variable is declared as a D3 selection and will be used for our transformations. We then append an SVG element to the DOM and include configurations to the output of our data with .attr. In this example our data is declared as an array but it could also be XML, JSON or just a plain CSV file. There are several other data formats we can use in D3. You can load a plain old text file, a TSV, HTML and even as an XmlHttpRequest. In order to add any elements at all we first have to create our SVG by declaring the area for our visual elements:

var svg = d3.select(‘div.myElement’)
    .append('svg')
    .attr(‘width’, ‘300 px’)
    .attr(‘height’, ‘300 px’);

Think of .select as the equivalent of $() in jQuery, which selects our div in this case. We declare our height and width as attributes for the SVG. D3 give us access to shapes like rectangles, circles, ellipses, lines, polygons and paths.

Adding Data
After we establish our canvas, we add our data. The utility functions available in D3 give us a wide coverage for creating powerful visuals. For example data() will load the data required for our document. We have the option of coding in our data but practical applications of D3 will most likely have us parsing data from a CSV or JSON file. A trivial use case would be declaring our data in the following examples:

As JSON

var dataset = {
    "first-name": “Hermes ",
    "last-name": “Trismegistus ",
};

Or as an array…

var dataset = [5, 10, 15, 20, 25];

var otherset = [{
    x: 100,
    y: 100
}, {
    x: 200,
    y: 200
}, {
    x: 300,
    y: 300
}]

If we wanted to load data from a CSV we’d do something like:

d3.csv("/data/data.csv", function(data) {
    console.log(data);
});

Once data is bound to the SVG we can use any number of included functions to create the graphical elements.

As a rule of thumb for data we should ensure that we can construct an array from the data we use. In next few steps we’ll cover several examples highlighting transformations in D3.

Bar chart aka Histogram

When you’d like to present data in the most efficient way possible, a histogram (better known as a bar chart) will work perfectly. Here’s a simple instance of a bar chart possible in D3:

In our fiddle example we prefix our rect element to build a bar graph using a rectangle: d3.append(“rect"). The rectangle appended to our SVG is used to represent data in our bar chart in the above fiddle as well as in most cases.

svg.selectAll("rect")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("x", function(d, i) {
        return i * (w / dataset.length);
    });

D3 subscribes to a declarative programming style. We make our selection, then configure any modifications as attributes within the DOM. This includes any changes to CSS styles, HTML, SVG attributes, texts and animations. D3 iterates through our selection, appends and applies modifications for us. The DOM is abstracted away while still granting us full control of the visualization processes.

Within our code example above we make use of selectAll() to create an empty set filled with our graphical elements:

svg.selectAll("text")
    .data(dataset)
    .enter()
    .append("text")
    .text(function(d) {
        return d;
    });

data() declares the object or array we will use to be represented in our chart. Then enter() combines our data with the empty set from selectAll() and creates a set of elements that can then be accessed by D3. append() which binds our selection and establishes the type of visualization by allowing us to choose from the available SVG elements. In this case, we want a ‘rect’ element to build a bar graph.

Next we define our bar with:

svg.selectAll('rect.bar').data(data)

An example of us positioning a bar chart based on our data, would look something like:

svg.append("rect") // append a rectangle 
    .attr("x", 100) // position the left of the rectangle 
    .attr("y", 50) // position the top of the rectangle 
    .attr("height", 100) // set the height 
    .attr("width", 200) // set the width

svg.selectAll('rect’) creates an empty set of rect elements.
.data(data) Adds object or array of data to be turned into elements in the DOM
.append('rect') Appends a ‘rect’ element for every item in data

attr() statements define what we want our bars to look like. Most importantly, they can use properties from each item in data. Before we add an axis to the graph, we’d probably need to define the start and end point. To do that we’d use xScale to define the scale of our chart:

var xScale = d3.scale
    .linear()
    .domain([0, data.length])
    .range([0, width]);

Tooltips

Whenever we have datapoint on a plot or a chart and there’s any semblance of interactivity, we can place tooltips on our visualization to provide context. Tooltips can let us mouse over bits of data within our chart and communicate without any other interaction. Tooltips are just chained pointer events. Here’s a simple implementation of tooltips in D3.js:

The secret to easily implementing tooltips in any visualization ultimately comes down to .on("mouseover”) and .on("mouseout”) events. Once we have our events setup, we simply chain animation attributes and listen for the end event. The .each() method is used to detect the end of each animation. If you’ve ever used jQuery you’ll recognize D3’s method chaining as strikingly familiar. Styles can change, attributes can be configured and elements appended by chaining methods.

Animations and Transitions
D3’s focus on transformation extends naturally to animated transitions. Animations or Transitions as they’re known in D3 are incredibly useful for conceptualizing deltas in datasets or providing interactivity. Transitions are described as interpolating styles and attributes that animate over time. D3 Transition methods animate DOM elements and carry them from a current state to an end state. Transitions occur over 4 phases – transition scheduled, started, run and ended. This “life cycle” is important to note when we use multiple animations on a single object of data. Here’s a simple example of an D3 animation:

Imagine that all transitions have a duration, Mike Bostock refers to transitions as having life and death cycles. D3 Transitions take a selection of elements, then it applies a transition to a part of the current state of the element, for each element. The d3.selection.transition method allows us to define what properties are changed, how the properties change, the length of time it takes for the transition to occur, when the transition starts after it is triggered and what the end state will look like.

Layouts

In D3 we utilize layout methods to encapsulate our visualizations. Layouts take data as an input and remap or otherwise transform it, generating new data that is more convenient for a specific visual task. Histogram, Cluster, Pie, Stack and Treemap layouts are just some of the layouts available.

One of the coolest applications of a layout is the Force layout. The Force layout is kind of graph diagram where positions of nodes are obtained by a simulation of forces. A Force layout is added as object and with select properties. Properties define the dimensions of the visualization as well as the arrays of nodes and links. Take a look at the Force layout in action:

D3 uses the this layout to create elements with forces acting on each node by all other nodes. You can configure the nodes to interact with each other based on the parsed data which would then appear as if each data node was pulling other nodes to a central point, within a user-defined space.

Force layout definitely adds some visual flash. Aside from the simple example provided here, the Force layout is one of the most commonly misused part of the D3 library. Any data visualization we create should present the data in a practical manner that is relevant and provides actual insight, not just for the sake of eye candy. Remember to use the force wisely.

Dashboard built with D3:

Ever wished to wow your colleagues armed with a single framework and your developer prowess? Well in my opinion here’s the most compelling reason to start using D3, rolling your own KPI dashboard. With D3 we’re able to combine the concepts we’ve covered above to provide an at-a-glance view of any data we feed into our dashboard.

If creating an entire dashboard based on KPI’s relevant to your C-Level executives isn’t enough, at the very least D3 lets you add a “Neat!” factor to any business presentation.

D3 provides a dynamic range of visual opportunities that aren’t possible with regular HTML DOM manipulation. The framework gives us a rich toolset for graphical data transformation and efficient manipulation of documents based on that data. The similarity to jQuery avoids us from learning proprietary API calls and affords us impressive flexibility within modern Web standards. D3 is the best JavaScript multipurpose SVG library when it comes to animation, interaction and above all for binding data to graphics. The community is very responsive, source code is very clean and the API is well written.

João SamoucoFullStack JavaScript Developer at Jscrambler.
View All Posts

Subscribe to our weekly newsletter

Learn more about new security threats and technologies.

I agree to receive these emails and accept the Privacy Policy.