D3 Basics: The Linear Scale
In the last post we did a basic introduction to the concept of scales in D3.js. Today we’ll look at our first scale and write some code to visualize it.
Linear Scales
The most basic scale in D3 is the linear scale
which maps a continous domain
to an output range. To define a linear domain we’ll need to first come up with a data set. Fibonacci numbers work well, so let’s declare a variable data
like so:
The data set will represent our scale’s input domain. The next step is defining an output range. Since we’re going to be graphing these numbers we want our range to represent screen coordinates. Let’s go ahead and declare a width
and a height
variable and set them to 320 by 150.
We now have everything we need to create our first scale.
D3 methods often return a value of self
meaning you can chain method calls onto one another. If you’re used to jQuery this should be a common idiom for you. You’ll notice that both the domain and the range functions accept arrays as parameters. Typically the domain only receives two values, the minimum and maximum of our data set. Likewise the range will be given the minimum and maximum of our output space. You could pass in multiple values to create a polylinear scale but that’s outside the scope of our dicussion today.
In the domain function we’re using a helper called d3.max
. Similar to Math.max
, it looks at our data set and figures out what is the largest value. While Math.max
only works on two numbers, d3.max
will iterate over an entire Array
for us.
If you’ve been following along in your own file you should be able to open your console and type x(8)
to get 300.
With just this information alone we have enough to build our first graph.
Fibonacci Sequence Chart 1.0
Break It Down
Let’s go through the JavaScript piece by piece to outline what happened.
The first block should be pretty familar at this point. We’ve declared our Fibonacci data, our explicit width and height and defined our scale. Nothing new here.
In the next section we’re declaring our SVG
element. We use a D3 selection to grab the body
tag and we append an svg
tag onto it. Since D3 uses method-chaining we can keep assigning attributes to our SVG element. We declare the width and the height to match the explicit values set earlier and finally we give it a class name of chart
.
This last section is where it all ties together. Since we stored our SVG element in a variable called svg
we’re able to easily reference it again. We instruct D3 to create a join
by calling the data
method and passing in our Array
of values. When D3 performs a join it steps through each element in the array and attempts to match it to a figure that already exists on the page. If nothing exists it will call the enter
function. At this point it steps through the array again, passing the values to us so we can define new shapes. For a much more in-depth explanation of joins refer back to this article.
In our case we’re appending SVG Rects
but it could just as easily be circles or other shapes. We give each rect a class of bar
so we can style it with CSS. When we declare the y
attribute instead of using an explicit value we create an accessor
, a little helper function which takes a piece of data and an optional index as its arguments. In this case d
will equal subsequent elements in our data array and i
will equal their indices. For a much clearer picture of what’s happening you can change it to read:
which will give you the following output.
Since we’re just trying to space out our bars along the y-axis we don’t really care about the value of d
. Instead we’ll use the index, i
, to offset each bar by a value of i * 20.
In the last two lines we’re going to finally use our linear scale to define our bar’s width. Here they are again as a refresher.
As each element of the array is passed to our width accessor it’s run through the scale and the output returned. Since 8 is our maximum value it should extend all the way to the end of our range.
The final call is just an explicit height for each bar. Depending on the scale this bit can be automated but for simplicity sake we’ll just use a hard coded value so we can get something on screen.
Conclusion
Now that we’ve got one scale under our belt the others should be pretty easy to digest. Over the next couple of posts we’ll focus on ordinal scales followed by time scales. Stay tuned and ping me if you have any questions. Thanks!
You should follow me on Twitter here.