Back to Contents Page

Scaling

Now that you know what you're going to be doing, it's time to dig into the D3 library. The first topic we need to talk about is scaling. Scaling isn't part of the D3 library, but is a technique that we employ to make sure that everything we're using is fitting on the same page. It involves a little bit of maths, but not too much!

When we start building visualizations, we need to identify our design goals. Visualizing, and graphics in general, can be difficult as it can be very punishing to plow ahead using trial and error. Minor variations in values can cause huge shifts in the results! One of the first things we need to do when writing D3 is to identify what our input is (our data), and what our expected output should be.

In a sense, we're extending the D3 library, by connecting methods to build our own functionality. When we design a presentation, like a bar chart, then we should be confident that it will work for any value. To show you exactly why this is important, let's imagine we have a small set of data, and we want to present it as a bar chart.

To write our bar chart we use the following code:

d3.select("#D3")
 .selectAll("div")
 .data(data)
 .enter().append("div")
    .attr("style", "outline: thin solid black;")
    .style("background-color", "red")
    .style("width", function(d) { return d * 10 + "px"; })
    .text(function(d) { return d; });

Which produces the following result:

There's a few things to notice here. One is draw order, which we haven't discussed because it's much better to see. In the example above, you can see that the borders of the bars on top of the graph are overlapping the bars below. This is because the borders project out from the div, and the precendence (top over bottom) is based on the order in which the div elements (used as bars here) were drawn. To avoid this we would either have to use a margin for all our div elements, or avoid using a border, maybe by using an alternating color scheme. More important than this minor quirk however, is the order of the methods in our script. Particularily the order of .style method calls.

Same calls override with often unpredictable effects unless you're familiar with the D3 library. The order is extremely important here. If we began by setting the width as a function of d, then the next style method would override the changed width, and we would no longer have a bar chart! The reverse is not true of the width call however, which doesn't alter the colors or borders of the bar. This is a difficult eccentricity of using libraries, which can only really be solved through practice and experience. In general it is best to define sizes last (as the most important factor, and then add other styling later.

What we really want to focus on is scaling. While the values we used displayed well (unless you have a tiny screen!) , what do you think would happen if we huge values? What if we were showing the travelling habits of 2million people? Well, we'd have a huge bar, which would go on, and on, and on. We need a method to make sure that everything fits within the space we allocate it, so that we can make sure than it's digestable in the users frame of reference.

The keyword here is actually reference. We want to make sure that everything in the graph is relative to a chosen maximum size. i.e, that everything in the graph in some way references a maximum index. The maths for this is really very simple (at least for a bar chart). The formula we would use is a simple ratio obtained using the following code.

var data = [2, 3, 17, 20, 23, 52];
var maxwidth = 100;
var max  = d3.max(data);
d3.select("#barchart1")
 .selectAll("div")
 .data(data)
 .enter().append("div")
     .attr("style", "outline: thin solid black;")
     .style("background-color", "red")
     .style("width", function(d) { return (d * maxwidth) / max + "%"; })
     .text(function(d) { return d; });
        

With this graph you can see that if you resize the window, it always remains within the box! The maximum index fills the box, and every other value is sized dynamically according to its size relative to the maximum. If we wanted, we could change the value to 80%, to give extra white space and maybe more context - but at least we've solved the overflow issue! (unless we set our width to over 100%).

One thing to note is that max($value) is not a d3 function. It's a JavaScript library function. To use it, we therefore have to chain from d3, so that the scope of max is the variables available to d3,

Now that you've seen the basics of how to scale d3, it's time to get underway! Experiment with using the max and min functions. You also have access to mean(), sum(), median() and extent() (gives [min, max] in an array) as well as a host of other included math functions. Remember that you're working towards a project, and it is competitive! Take risks, and try to stay outside your comfort zone. You might want to start planning with your partner what interests you, what kind of data you'd like to use and what you could visualize. Be ambitious! There a huge amount of materials online, and a lot of widely available example code to explore. (Though please don't plagiarize whole blocks of code!)

Author : Ben Ryves