On This Page...

Week 3: Data Loading, Tables

Homework Review

Two Charts

Nice comparisons:

Nice text:

But note: the dual-axis problem is a real one: https://www.perceptualedge.com/articles/visual_business_intelligence/dual-scaled_axes.pdf

Try to avoid using them!

What was hard about this homework?

An In-Class Debugging Problem

Let's look at the error in jquery_error_on_load.html together.

Some Javascript Manipulations on Data

Data Processing on Load (and Scope)

It's quite common to do things to your data right after you load it. Very useful ways to iterate through data include dataset.forEach(function (d,i) {...}) and map: dataset.map(function (d,i) {...}). Have a look at http://learnjsdata.com/iterate_data.html.

Remember that in d3, you need ALL your work on data to occur inside the d3.csv() function call. Otherwise, the data variables will not be visible to your code and you will get errors that things are undefined.

d3.csv('myfile.csv', function(error, data) {

    if (error) {
        console.log("Error on load:", error);
    }

// in here, data is defined! Unless you had an error on
// load.


});

Sorting Data Arrays

Useful javascript for sorting, by the way - and the sort order depends on whether you do a-b or b-a. This notation works with sorting an array of objects, which means they have the attribute "difference" on them:

data.sort(function(a,b) {
    return b.difference-a.difference;
});

The sort function will sort an array in place - meaning, the data array is now sorted for you after you call this function (it persists).

Also, in d3, there are some utility methods - if you use these, make sure your data values are numeric, though (unless you want sorting by string value, or alphabetic). This shows us sorting an array of objects by the attribute "value":

data.sort(function (a, b) {
    return d3.ascending(a.value, b.value);
}

A trick to get your data to be numeric is to use a + in front of it, which is type coercion.You will see this all the time in D3 code.

data.sort(function (a, b) {
    return d3.ascending(+a.value, +b.value);
}

If you have an array of numbers or strings, not objects, your sort needs to work differently:

    arrays = [
        [2,4,5,6,8, "china"],
        [1,4,7,8,90,4, "australia"],
        [34,44,23,54,65,5, "belgium"],
        [3,4,54,2,4,5,6,"france"]
    ];

    //To sort by the item in the 3rd column:

    arrays.sort(function(a, b) {
        return b[2] - a[2];
    })

    //or

    arrays.sort(function(a,b) {
        return d3.descending(a[2], b[2]);
        })

Again, alphabetic sorting can use the same d3 helper functions!

Dates in Your Data (a First Glance)

Dates should be turned into Javascript date objects. D3 has tools for this. A lot of the data from UNICEF includes dates (years, anyway).

The thing to remember is that you need to "parse" a date string to make a Javascript date object. You can then convert it to another format to print out a human readable string.

    var dateParser = d3.time.format("%Y"); // this is 2007 etc, as in the file.
    var outputDate = d3.time.format(" '%y "); // this is '07 format - with spaces around it

We "parse" using the .parse() function on the dateParser we set up with a format:

    // you apply the function with parse, to read it in:
    d.parsed_year = dateParser.parse(d.year);

To print it, we just wrap the parsed year in the output format we want:

console.log("output string:", outputDate(d.parsed_year));

For more:

We'll come back to dates in an upcoming week, too.

Intro to Selections and Data Binding in D3

To do the "right" thing with data in D3, you need to understand binding data to DOM elements. This concept works with the "selectAll, bind data, enter, append what you selected" pattern.

Data binding in D3 uses a pattern in which we select a non-existent element on the page, bind the data to it with a .data() statement, enter() it, and then append the thing we selected, for each row of data.

The pattern for multiple rows of data in a file is always:

var table = d3.select("#table");  // select the thing on the page you are attaching to

// we use the svg element to attach our 
table.selectAll("p") // or whatever svg or DOM element you want to create!
    .data(myData) // using your data set here - this is the binding
    .enter() // this is used to "enter" each row of your data
    .append("p") // now create a p for it
    .text(function(d) {  //  use a data element to fill in the text here. function(d) is always your data item.
        return d.SomeProperty;
    });

For data and charts that will be updated, the best pattern to follow is to bind the data separately from the enter stage - because you might be also calling transition and exit on that data selection. (You'll see that later.)

var mytable = table.selectAll("p")
    .data(myData); // this is a data binding in a separate step.

mytable.enter()
    .append("p")
    .text(function(d) {
        return d.someProperty;
    });

Important Readings:

If you remain confused, try these till you get a grip:

Tables as an Intro to "Deep" D3 Thinking

We're starting with tables, because in my opinion they are an often overlooked part of the interactive vis landscape, and one of my favorites. Building them illustrate some key aspects of D3 DOM manipulation, they allow us to use JQuery and D3 together if we want; they transition nicely to heatmaps, an excellent visual display method for some types of data.

There is a special case for binding a single item of data, using datum() instead of the data() with the select/enter pattern. Datum will bind one item, and does not use an "enter()" function; you can still access the data in subsequent chained clauses using an append and the function(d) accessor to get attributes of the data. This is an example:

var table = d3.select("#data"); // we will work from the #table div on the page, and attach data to it.
var header = table.append("p").attr("class", "header");

// then we attach a single data item to it - an array of strings.
header
    .datum(["Region", "1990", "2015", "Difference"])
    .text(function(d) {
        return d.join(" ");  // this is the same as making a string like:
                             // d[0] + ' ' + d[1] + ' ' + d[2] + ' ' + d[3], 
                             //except we don't need to know how many items are in the array!
    });

For more on the data() vs. datum() difference, see the datum documentation and this thread on SO.

A little more complex in the packaging:

Homework

Readings:

Plus anything else that I referenced above that helps you better understand d3 data selection and joins.

Homework: (25pt), Build your own styled table from your own CSV data, using the model in d3_tabulate_function.html.

When you make the gist, you will need to upload the file tabulate.js too!

Send me the gist: "Week 3: D3 Table."