Tuesday, March 19, 2024

Bring Your Data to Life with D3.js

Let’s face it, raw data is boring. Moreover, it can be a challenge to spot patterns in reams of textual format. Visuals are far easier to interpret. Humans tend to be visual by nature, so putting data in a graphical context makes it much easier to spot trends.

There are a few data visualization libraries, but one in particular that has been gaining a lot of traction of late is D3. Short for Data-Driven Documents, D3 is a JavaScript library for producing dynamic, interactive data visualizations in any web browser. It makes use of the widely implemented SVG, HTML5, and CSS standards. In contrast to many other libraries, D3.js gives you tremendous control over the final result.

In today’s tutorial we’ll use the D3.js library to display the contents of a CSV data file within a dynamically generated HTML table.

Loading the Data

Our data is a CSV dump of the films from the Sakila Sample Database. It’s one of my favorite data sources because its content is entertaining as heck!

 

“film_id”,”title”,”description”,”release_year”,”rental_rate”,”length”,”rating” “1”,”ACADEMY DINOSAUR”,”A Epic Drama of a Feminist And…”,”2006″,”0.99″,”86″,”PG” “47”,”BABY HALL”,”A Boring Character Study of a A Shark And a Girl who must…”,”2006″,”4.99″,”153″,”NC-17″ “110”,”CABIN FLASH”,”A Stunning Epistle of a Boat And a Man who…”,”2006″,”0.99″,”53″,”NC-17″

D3’s d3-fetch module provides convenient parsing on top of the whatwg Fetch spec. It includes Ajax-powered methods for retrieving data in a variety of formats, from text and csv to blobs, images, json, and whatever data types you might want to load.

For example, d3.csv() converts the raw data into an array of objects:

d3.csv("sakila_videos.csv").then(function(data) {
  console.log(data[0]); /* => {
                             film_id: "1", 
                             title: "ACADEMY DINOSAUR", 
                             description: "A Epic Drama of a Feminist And…", 
                             release_year: "2006", 
                             rental_rate: "0.99", 
                             length: "86",
                             rating: "PG"
                           } */
});

What if you don’t want an array of objects? Another option is to use the d3.text() method. It treats the data as a string:

d3.text("sakila_videos.csv").then(function(data) {
  console.log(data); 
/* 
"film_id","title","description","release_year","rental_rate","length","rating"
"1","ACADEMY DINOSAUR","A Epic Drama of a Feminist And…","2006","0.99","86","PG"
"47","BABY HALL","A Boring Character Study of a A Shark And a Girl who must…" etc…
*/
});

From there, we can use the d3.csvParseRows(). It converts the CSV string into an array (rows) of arrays (columns):

d3.text("sakila videos.csv").then(function(data) {
  var rows  = d3.csvParseRows(data);
  console.log(rows);
/*
0:Array(7)
  0:"film_id"
  1:"title"
  2:"description"
  3:"release_year"
  4:"rental_rate"
  5:"length"
  6:"rating"
1:Array(7)
  0:"1"
  1:"ACADEMY DINOSAUR"
  2:"A Epic Drama of a Feminist And…"
  3:"2006"
  4:"0.99"
  5:"86"
  6:"PG"
2:Array(7)
0:"47"
1:"BABY HALL"
2:"A Boring Character Study of a A Shark And a Girl who…"
3:"2006"
4:"4.99"
5:"153"
6:"NC-17"
etc…
*/
});

Rendering the Table and Headers

You’ll find that working in HTML format with D3 is very similar to jQuery. D3 has a select() method for selecting a single DOM element as well as a style() method for…er…styling elements.

Here’s the code for appending the table to the DOM:

var rows  = d3.csvParseRows(datasetText),
    table = d3.select('body').append('table')
    .style("border-collapse", "collapse")
    .style("border", "2px black solid");

With a reference to the table, we can now add the headers:

// headers
table.append("thead").append("tr")
    .selectAll("th")
    .data(rows[0])
    .enter().append("th")
    .text(function(d) { return d; })
    .style("border", "1px black solid")
    .style("padding", "5px")
    .style("background-color", "lightgray")
    .style("font-weight", "bold")
    .style("text-transform", "uppercase");

An Explanation of some of the Above Methods

There are a lot of method calls in the above code snippet, some of which require further elucidation:

  • selection.selectAll(selector): Selects the descendant elements that match the specified selector string for each selected element – similar to jQuery find().
  • selection.data([data[, key]]): Joins the specified array of data with the selected elements, returning a new selection that represents the updated selection.
  • selection.enter(): Identifies any DOM elements that need to be added when the joined array is longer than the selection. It’s defined on an update selection (i.e., the selection returned by .data() ):
  • selection.text([value]): Sets the text content to the specified value on all selected elements, replacing any existing child elements. If the value is a constant, then all elements are given the same text content. The method can also accept a function, in which case the value is evaluated for each selected element, in order, being passed the current method call (d). The function’s return value is then used to set each element’s text. Meanwhile, a null (or no) value clears the content.

Appending the Data Rows

The exact process that we followed to add the headers can again be applied to the data rows:

// data
table.append("tbody")
    .selectAll("tr").data(rows.slice(1))
    .enter().append("tr")
    .selectAll("td")
    .data(function(d){return d;})
    .enter().append("td")
    .style("border", "1px black solid")
    .style("padding", "5px")
    .text(function(d){return d;})
    .style("font-size", "12px");

Here is the final product in Codepen. Note that it includes mouseover cell highlighting(!):

Going Forward

In today’s tutorial we used the D3.js library to display the contents of a CSV data file within a dynamically generated HTML table. In the next article, we’ll get a taste for D3’s SVG prowess by constructing a slick stock chart.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured