Creating Interactive Charts With D3.js

D3.js is a powerful JavaScript library for real time manipulation of data-driven documents. Combining JS, HTML, SVG and CSS, D3 makes it possible to create beautiful visualizations — fueled by data — that the end consumer can interact with.

I learned D3 over a weekend last summer, for a project at LookBookHQ; and decided to make this tutorial to help others out there who are starting out, and likely have the same questions (and headaches?) I did. D3 is potentially challenging and has a rather steep learning curve; however, once you are up to speed with its core classes and functions, it is quite fun and you won’t want to stop. (Nerd alert.)

There are some great tutorials out there (links at the bottom) that delve into the intricacies of D3, but my focus here is using D3  — along with a couple of other JS libraries — to create a multi dimensional nested data visualization in just a few minutes. The assumption here is that you are already familiar with web development, and know your way around JavaScript, HTML, and CSS; as well as tools like Developer Tools/Web Inspector in modern browsers like Chrome.

Here is what the final product looks like. A link to the downloadable source code is available at the bottom.

All right, turn the music on, brew some tea, and let’s go.

Create a new directory or folder for your project. Download D3 and place it in a subfolder within your main folder.

Create a HTML file, and name it accordingly; for example, index.html. Inside the <head> tag of your HTML file, copy and paste a reference to the D3 location in a script tag as follows:

script type="text/javascript" src="d3.v2.min.js"></script>

Also within the <head> tag, include a reference to JQuery, another powerful JS library that has made life better for many, many good people out there. You can choose to make a remote reference to the code hosted on Google, as I have done below; or you can download it and make a reference to the file within your folder.

script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>


I will also use HighCharts.js (a D3-based JavaScript library) here, to take advantage of its additional charting functionality. I am attempting here to make a nested bar chart depicting a range of numerical values (y) for each time period (x) against a set of indicators (zi) per variable (z).

A standard chart would allow for the charting of y/x; however, this chart will go further, showing change across the categorical groupings, and allowing us to zoom into each category and view the relationship between a time period and a respective numerical value; thus, allowing for in-depth analysis.

In other words: For each variable z, we can see the change y over time periods x, for every set of indicators, zi. First, we will initiate the chart object, and load the DOM with some simple jQuery code below.


$(function () {
    var chart;
    $(document).ready(function() {
        chart = new Highcharts.Chart({
            chart: {
                renderTo: 'overview',
                type: 'column',
                zoomType: 'x'
            },
            title: {
                text: 'Our interactive chart' //title of the chart.
            },
            xAxis: {
                categories: ['Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2','Year 1', 'Year 2'],

Now we add the indicators, using “plotbands” to group them together. The x-axis points are used to define the width and position of the groups. I have used 2 points for each group in this case; giving us a first one (colour: dark grey) from -0.5 to 1.5, and a second group (colour: light grey) from 1.5 to 3.5, (and a third group, and so, on…) on the x-axis.

plotBands: [
            {
            color: '#333',
            from: -0.5,
            to: 1.5,
            label: {
                text: 'Indicator 1',
                align: 'center',
                font: '7px',
                verticalAlign: 'top',
             style: {
                color: '#fff',
                font: '7px',
                fontWeight: 'none'
             }
            }},
        {
            color: '#666666',
            from: 1.5,
            to: 3.5,
            label: {
                text: 'Indicator 2',
                align: 'center',
                verticalAlign: 'top',
                style: {
                    color: '#fff'
                }
            }},


Here, we specify the values for each point on the x axis, corresponding to the form year 1, year 2, year 1, year 2used earlier.

series: [{
     name: 'Variable 1',
     data: [7.97,8.28,9.1,9.22,8.71,8.95,8.21,7.77,6.38,7.17,6.02,7.86,6.7,7.79,8,9,8.13,8.04],}, {
     name: 'Variable 2',
     data: [7.65,8.26,7.73,7.85,8.16,7.96,7.77,7.51,5.79,6.28,6.11,7.58,6.62,7.41,8.03,9,7.67,7.59]}, {
     name: 'Variable 3',
     data: [7.03,7.99,6.72,7.33,6.54,6.03,5.71,6.67,5,4.77,4.74,6.3,6.14,6.09,8.32,9,7,6.93]}, {
     name: 'Variable 4',
     data: [6.69,7.7,7.22,6.58,7.25,7.42,6.97,6.81,4.38,4.81,4.17,6.69,5.68,6.61,6.94,7.93,7.24,7.82] 
}]


Now comes the fun part. We previously enabled the mouseover that shows the value of each individual column, and we want to take it a step further: drilling into each column. In the code snippet below, I have replaced the first value in the array, 7.97, with {y:7.97,url:’zoomin1.html’}. This is an array that specifies the value, 7.97, and a URL which will be launched when the column is clicked.

In this case, the URL is the address of the page that contains a chart with data that zooms into variable 1 of indicator 1 for year 1. And it could have been anything; perhaps a cat video that was somehow relevant to that particular item on our visualization. The idea is to make this interactive, by allowing the consumer to zoom into the chart, to reveal deeper underlying data — as we’ve done in this case — or merely adding more context, by means of an external file or web page.

series: [{
     name: 'Variable 1',
     data: [{y:7.97,url:'zoomin1.html'},{y:8.28,url:'zoomin1.html'},{y:9.1,url:'zoomin1.html'},{y:9.22,url:'zoomin1.html'},{y:8.71,url:'zoomin1.html'},{y:8.95,url:'zoomin1.html'},{y:8.21,url:'zoomin1.html'},{y:7.77,url:'zoomin1.html'},{y:6.38,url:'zoomin1.html'},{y:7.17,url:'zoomin1.html'},{y:6.02,url:'zoomin1.html'},{y:7.86,url:'zoomin1.html'},{y:6.7,url:'zoomin1.html'},{y:7.79,url:'zoomin1.html'},{y:8,url:'zoomin1.html'},{y:9,url:'zoomin1.html'},{y:8.13,url:'zoomin1.html'},{y:8.04,url:'zoomin1.html'}],}, {
     name: 'Variable 2',
     data: [{y:7.65,url:'zoomin2.html'},{y:8.26,url:'zoomin2.html'},{y:7.73,url:'zoomin2.html'},{y:7.85,url:'zoomin2.html'},{y:8.16,url:'zoomin2.html'},{y:7.96,url:'zoomin2.html'},{y:7.77,url:'zoomin2.html'},{y:7.51,url:'zoomin2.html'},{y:5.79,url:'zoomin2.html'},{y:6.28,url:'zoomin2.html'},{y:6.11,url:'zoomin2.html'},{y:7.58,url:'zoomin2.html'},{y:6.62,url:'zoomin2.html'},{y:7.41,url:'zoomin2.html'},{y:8.03,url:'zoomin2.html'},{y:9,url:'zoomin2.html'},{y:7.67,url:'zoomin2.html'},{y:7.59,url:'zoomin2.html'}]}, {
     name: 'Variable 3',
     data: [{y:7.03,url:'zoomin3.html'},{y:7.99,url:'zoomin3.html'},{y:6.72,url:'zoomin3.html'},{y:7.33,url:'zoomin3.html'},{y:6.54,url:'zoomin3.html'},{y:6.03,url:'zoomin3.html'},{y:5.71,url:'zoomin3.html'},{y:6.67,url:'zoomin3.html'},{y:5,url:'zoomin3.html'},{y:4.77,url:'zoomin3.html'},{y:4.74,url:'zoomin3.html'},{y:6.3,url:'zoomin3.html'},{y:6.14,url:'zoomin3.html'},{y:6.09,url:'zoomin3.html'},{y:8.32,url:'zoomin3.html'},{y:9,url:'zoomin3.html'},{y:7,url:'zoomin3.html'},{y:6.93,url:'zoomin3.html'}]}, {
     name: 'Variable 4',
     data: [{y:6.96,url:'zoomin4.html'},{y:7.7,url:'zoomin4.html'},{y:7.22,url:'zoomin4.html'},{y:6.58,url:'zoomin4.html'},{y:7.25,url:'zoomin4.html'},{y:7.42,url:'zoomin4.html'},{y:6.97,url:'zoomin4.html'},{y:6.81,url:'zoomin4.html'},{y:4.38,url:'zoomin4.html'},{y:4.81,url:'zoomin4.html'},{y:4.17,url:'zoomin4.html'},{y:6.96,url:'zoomin4.html'},{y:5.68,url:'zoomin4.html'},{y:6.61,url:'zoomin4.html'},{y:6.94,url:'zoomin4.html'},{y:7.93,url:'zoomin4.html'},{y:7.24,url:'zoomin4.html'},{y:7.28,url:'zoomin4.html'}] 
}]


There are many interesting things we can do additionally, such as using D3’s CSV parser to input a CSV file, which would then be converted to arrays, just like I did in this tutorial. I’ll save that for another time. (Part two?).

I have made the source code for this project freely available on GitHub, under an MIT Open Source license.

LINKS:

Official D3.js

Tutorial by Luke Francl

Tutorial by Christophe Viau

Tutorial by Dashing D3