D3 Tips and Tricks v4

Monday, 31 December 2012

New Version of D3 Tips and Tricks (ver 0.2.b)

The latest version of D3 Tips and Tricks is out (New Years Edition).

There's two versions of the simple line graph. One with little or no commenting and the other that is HEAVILY commented that people may find useful. Additionally, there is a zip file with the directory structure that I've been using for the examples and some of the example / data files as well. As time allows I will add to these.

As appears to be working so far, just click on the link on the left on the main page and you can download the pdf from there. or go to the downloads page.

Just a quick note as well... The process I am using to try and maintain a common point for downloading the pdf in drop box appears to cause it to fail to load the pdf when you go to download it the first time. DONT DESPAIR. Just reload and it appears. I will have to sort this out I know. I think I'll try to store it as a publicly accessible document in Google Drive in future releases.

I have also started to learn how to host files in GitHub / Gist, so expect to see more there over time.

Changelog:

Selecting a particular object or set of objects using the .filter function.
Select items with an IF statement
Using Plunker for online development and hosting your D3 creations.
Adding a thumbnail to a Gist for bl.ocks.org D3 graphs

Loading a thumbnail into Gist for bl.ocks.org d3 graphs


The following post is a portion of the D3 Tips and Tricks document which it free to download. To use this post in context, consider it with the others in the blog or just download the pdf  and / or the examples from the downloads page:-)
--------------------------------------------------------

This description will start on the assumption that the user already has a GitHub / Gist account set up and running. It's purpose is to demonstrate how to upload an image as a file named thumbnail.png to a Gist so that when viewing the users home page on bl.ocks.org you see a nice little preview of what a visitor can anticipate when they go toy look at your work :-)

This description is a fleshed out version of the one provided by Christophe Viau on Google Groups (https://groups.google.com/forum/?fromgroups=#!topic/d3-js/FBosXiTB9Pc).

Setting the scene:

There you are a fresh faced d3.js user keen to share your work with the world. You set yourself up a GitHub / Gist account and put your code into a gist.  
Your graph is a thing of rare beauty and the community needs to marvel at your brilliance. Of course this is a breeze with bl.ocks.org. Once you have all the code sorted and any data files accessible, bl.ocks.org can display the graph with the code and can even open the graph in its own window. The person responsible for bl.ocks.org? Mike Bostock of course (wherever does he get the time?).

So clicking on the bl.ocks.org button on the gist page takes you to see your graph.
Wow! Impressive.

So you think that will make a fine addition to your collection of awesome graphs and if you click on your GitHub user name that is in the top left of the screen you go to a page that lays out all your graphs with a thumbnail giving a sneak preview of what the user can expect.
Aww... Rats! There's a nice place holder, but no pretty picture.

Hang on, what had Mike said on the bl.ocks.org main page?

The main source code for your example should be named index.html. You can also include a README.md using Markdown, and a thumbnail.png for preview.

Ahh.. you need to include a thumbnail.png file in your Gist!

So how to get it there? Well Gist is a repository, so what you need to do is to put the code in there somehow. Now from the Gist web page this doesn't appear to be a nice (gui) way to do this. So from here you will need to suspend your noob status and hit the command line.

The good news (if you're a windows user (and sorry, I haven't done this in Linux or on a Mac)) is that as part of the GitHub for windows installation a command line tool was installed as well! So you're going to use the Git Shell.

Enough of the scene setting. Let's git going :-).

Right, I'm going to describe the steps here in a pretty verbose fashion with pretty pictures and everything, but at the end I will put a simple set of steps in the form that Christophe Viau outlined on Google Groups.

First you will want to have your image ready. It needs to be a png with dimensions of 230 x 120 pixels. It should also be less than 50kB in size.

Now go to your public Gist that you have already set up and copy the link in the “Clone this gist” box.
(this should look something like https://gist.github.com/4414436.git)

Now you're going to clone this gist to a local repository using the Git Shell. Open it up from the desktop icon and you should see something like the following;
So you can clone the gist to a local folder with the command;
git clone https://gist.github.com/4414436.git

(or if you're using OSX, Alex Hornbake (see comments) has mentioned that the following command should be used to clone the gist using ssh (Thanks Alex!))

git clone git@gist.github.com:4414436.git

(The url is the one copied from the 'Clone this gist' box.)
 This will create a folder with the id (the number) of the gist in your local GitHub working directory.
And there it is (Ooo... Look almost New Years!).

Copy your thumbnail.png file into this directory.

Back to the Git Shell and change into the directory (4414436) . We can now add the thumbnail.png file to the gist with the command;
git add thumbnail.png

And now commit it to your gist with the following command in the Git Shell;
git commit -m "Thumbnail image added"

Now we need to push the commit to the remote gist (you may be asked for your GitHub user name and password if you haven't done this before) with the following command;
git push

OK, now you can go back to the web page for your gist and refresh it and scroll on down...
Woo Hoo!

(I know it doesn't look like much, but this is a VERY simple graph :-)).

Now for the real test. Go back to your home page for your blocks on bl.ocks.org and refresh the page.
Oh yes. You may now bask in the sweet glow of victory. And as a little bit of extra fancy, if you move your mouse over the image it translates up slightly!

Wrap up.

The steps to get your thumbnail into the gist aren't exactly point and click, but the steps you need to take are fairly easy to follow. As promised, here is the abridged list of steps that will avoid you going through the several previous pages.
  1. Create your public gist on https://gist.github.com/
  2. Get an image ready (230 x 120 pixels, named thumbnail.png)
  3. Under "Clone this gist", copy the link (i.e., https://gist.github.com/4414436.git)
  4. If you have the command line git tools (Git Shell), clone this gist to a local folder:
    git clone https://gist.github.com/4414436.git (or git clone git@gist.github.com:4414436.git  for OSX)
    It will add a folder with the gist id as a name (i.e., 4414436) under the current working directory.
  5. Navigate to this folder via the command line in Git Shell: cd 4414436 (dir 4414436 on windows)
  6. Navigate to this folder in file explorer and add your image (i.e., thumbnail.png)
  7. Add it to git from the command line: git add test.png
  8. Commit it to git: git commit -m "Thumbnail added"
  9. Push this commit to your remote gist (you may need your Github user name and password):
    git push
  10. Go back and refresh your Gist on https://gist.github.com/ to confirm that it worked
  11. Check your blocks home page and see if it's there too. http://bl.ocks.org/<yourusername>
Just to finish off. A big thanks to Christophe Viau for the hard work on finding out how it all goes together and if there are any errors in the above description I have no doubt they will be mine.


The above description (and heaps of other stuff) is in the D3 Tips and Tricks document that can be accessed from the downloads page of d3noob.org.

Sunday, 30 December 2012

Adding axis labels to a d3.js graph

The following post is a portion of the D3 Tips and Tricks document which is free to download from the main page.
---------------------------------------------------------


What's the first thing you get told at school when drawing a graph?

“Always label your axes!”

So, time to add a couple of labels!

First things first (because they're done slightly differently), the x axis. If we begin by describing what we want to achieve, it may make the process of implementing a solution a little more logical

What we want to do is to add a simple piece of text under the x axis and in the centre of the total span. Wow, that does sound easy.

And it is, but there are different ways of accomplishing it, and I think I should take an opportunity to demonstrate them. Especially since one of those ways is a BAD idea.

Lets start with the bad idea first :-).

This is the code we're going to add to the simple line graph script;
svg.append("text")      // text label for the x axis
        .attr("x", 265 )
        .attr("y",  240 )
        .style("text-anchor", "middle")
        .text("Date");
We will put it in between the blocks of script that add the x axis and the y axis.
svg.append("g")         // Add the X Axis
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    //  PUT THE NEW CODE HERE!

    svg.append("g")         // Add the Y Axis
        .attr("class", "y axis")
        .call(yAxis);
Before we describe what's happening, let's take a look at the result;
Well, it certainly did what it was asked to do. There's a 'Date' label as advertised! (Yes, I know it's not pretty.) Let's describe the code and then work out why there's a better way to do it.
svg.append("text")      // text label for the x axis
        .attr("x", 265 )
        .attr("y", 240 )
        .style("text-anchor", "middle")
        .text("Date");
The first line appends a "text" element to our canvas. There is a lot more to learn about "text" elements here; http://www.w3.org/TR/SVG/text.html#TextElement.

The next two lines ( .attr("x", 265 ) and .attr("y", 240 ) ) set the attributes for the x and y coordinates to position the text on the canvas.

The second last line (.style("text-anchor", "middle")) ensures that the text 'style' is such that the text is centre aligned and therefore remains nicely centred on the x,y coordinates that we send it to.

The final line (.text("Date");) adds the actual text that we are going to place.

That seems really simple and effective and it is. However, the bad part about it is that we have hard coded the location for the date into the code. This means if we change any of the physical aspects of the graph, we will end up having to re-calculate and edit our code. And we don't want to do that.

Here's an example. If I decide that I would prefer to increase the height of the graph by editing the line here;
height = 270 - margin.top - margin.bottom;
and making the height 350 pixels;
height = 350 - margin.top - margin.bottom;
The result is as follows;
EVERYTHING about the graph has adjusted itself, except our nasty, hard coded 'Date' label. This is far from ideal and can be easily fixed by using the variables that we set up ever so carefully earlier.

So, instead of;
.attr("x", 265 )
        .attr("y", 240 )
lets let our variables do the walking and use;
.attr("x", width / 2 )
        .attr("y",  height + margin.bottom)
So with this code we tell the script that the 'Date' label will always be halfway across the width of the graph (no matter how wide it is) and at the bottom of the graph with respect to it's height and the bottom margin (remember it uses a coordinates system that increases from the top down).

The end result of using variables is that if I go to an extreme of changing the height and width of my graph to;
width = 400 - margin.left - margin.right,
    height = 200 - margin.top - margin.bottom;
We still get an acceptable result;
Well, for the label position at least :-).

So the changes to using variables is just a useful lesson that variables rock and mean that you don't have to worry about your graph staying in relative shape while you change the dimensions. The astute readers amongst you will have learned this lesson very early on in your programming careers, but it's never a bad idea to make sure that users that are unfamiliar with the concept have an indicator of why it's a good idea.
Now the third method that I mentioned at the start of our x axis odyssey. This is not mentioned because its any better or worse way to implement your script (The reason that I say this is because I'm not sure if it's better or worse.) but because it's sufficiently different to make it look confusing if you didn't think of it in the first place.

So, we'll take our marvelous coordinates code;
.attr("x", width / 2 )
        .attr("y",  height + margin.bottom)
And replace it with a single (longer) line;
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")")
This uses the "transform" attribute to move (translate) the point to place the 'Date' label to exactly the same spot that we've been using for the other two examples (using variables of course).
Things to note about this piece of code;

The "translate” function is done in a 'translate(x,y)' style but it is put on the page in such a way that the verbatim pieces that get passed back are in speech marks and the variables are in the clear (in a manner of speaking). That's why the comma is in speech marks.

Additionally, the variables are contained within plus signs. I make the assumption that this is a designator for 'areas where there is variable action going on'. The end result is that if you try to do some maths in that area with a plus sign, it does not appear to work (or at least it didn't for me). That's why I put the variable for ( + (height + margin.bottom) + ) in parenthesis (then I thought I should make the + (width / 2) + part look the same, but actually you can get away without them there).

So, that's the x axis label. Time to do the y axis. The code we're going to use looks like this;
svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 – margin.left)
        .attr("x",0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("Value");
For the sake of neatness we will put the piece of code in a nice logical spot and this would be following the block of code that added the y axis (but before the closing curly bracket)
svg.append("g")         // Add the Y Axis
        .attr("class", "y axis")
        .call(yAxis);

    // PUT THE NEW CODE HERE!

});
And the result looks like this;
There we go, a label for the y axis that is nicely centred and (gasp!) rotated by 90 degrees! Woah, does the leetness never end! (No. No it does not.)

So, how do we get to this incredible result?

The first thing we do is the same as for the x axis and append a test element to our canvas (svg.append("text")).

Then things get interesting.
.attr("transform", "rotate(-90)")
Because that line rotates everything by -90 degrees. While it's obvious that the text label 'Value' has been rotated by -90 degrees (from the picture), the following lines of code show that we also rotated our reference point (which can be a little confusing).
.attr("y", 0 – margin.left)
        .attr("x",0 - (height / 2))
Let's get graphical to illustrate how this works;
Here's our starting position, with x,y in the 0,0 coordinate of the graph drawing area surrounded by the margins.

When we apply a -90 degrees transform we get the equivalent of this;
Here the 0,0 coordinate has been shifted by -90 degrees and the x,y designations are flipped so that we now need to tell the script that we're moving a 'y' coordinate when we would have otherwise been moving 'x'.

Hence, when the script runs...  
.attr("y", 0 – margin.left)
… we can see that this is moving the x position to the left from the new 0 coordinate by the margin.left value.
 
Likewise when the script runs...
.attr("x",0 - (height / 2))
… this is actually moving the y position from the new 0 coordinate halfway up the height of the graph area.

Now, I will be the first to admit that this does seem a little confusing, but here's the good part. You really don't need to understand it completely. Simply do what I did when I saw the code. Play with is a bit till you get the result you were looking for. If that means putting in some hard coded numbers and incrementing them to see which way is the new 'up'. Good! Once you work it out, then work out how to get the right variable expression in there and you're set.

In the worst case scenario, simply use the code blocks as shown here and leave well enough alone :-)
Right, we're not quite done yet. The following line has the effect of shifting the text slightly to the right.
.attr("dy", "1em")

Firstly the reason we do this is that our previous translation of coordinates means that when we place our text label it sits exactly on the line of 0 – margin.left. But in this case that takes the text to the other side of the line, so it actually sits just outside the boundary of the overall canvas.

The "dy" attribute is another coordinate adjustment move, but this time a relative adjustment and the "1em" is a unit of measure that equals exactly one unit of the currently specified text point size (http://en.wikipedia.org/wiki/Em_(typography)). So what ends up happening is that the 'Value' label gets shifted to the right by exactly the height of the text, which neatly places it exactly on the edge of the canvas.

The two final lines of this part of the script are the same as for the x axis and they make sure reference point is aligned to the centre of the text (.style("text-anchor", "middle")) and then it prints the text (.text("Value");). There, that wasn't too painful.

Many thanks the the eagle eyed reader that spotted that the code for this example wasn't available for download. Although this isn't the perfect resolution, here is the code in full;
<!DOCTYPE html>
<meta charset="utf-8">
<style>

body { font: 12px Arial;}

path { 
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}

.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}

</style>
<body>
<script type="text/javascript" src="d3/d3.v3.js"></script>

<script>

var margin = {top: 30, right: 20, bottom: 30, left: 50},
    width = 600 - margin.left - margin.right,
    height = 270 - margin.top - margin.bottom;

var parseDate = d3.time.format("%d-%b-%y").parse;

var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

var valueline = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });
    
var svg = d3.select("body")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// Get the data
d3.tsv("data/data.tsv", function(error, data) {
    data.forEach(function(d) {
        d.date = parseDate(d.date);
        d.close = +d.close;
    });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([0, d3.max(data, function(d) { return d.close; })]);

    svg.append("path")      // Add the valueline path.
        .attr("class", "line")
        .attr("d", valueline(data));

    svg.append("g")         // Add the X Axis
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Add the text label for the x axis
    svg.append("text")
        .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")")
        .style("text-anchor", "middle")
        .text("Date");

    svg.append("g")         // Add the Y Axis
        .attr("class", "y axis")
        .call(yAxis);

    // Add the text label for the Y axis
    svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x",0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("Value");

});

</script>
</body>



-------------------------------------------------------------
The above description (and heaps of other stuff aimed at helping those with limited understanding, but plenty of desire to play with D3) is in the D3 Tips and Tricks document that can be accessed from the main page of d3noob.org.  

Saturday, 29 December 2012

Using Plunker for development and hosting your D3 creations


The following post is a portion of the D3 Tips and Tricks document which it free to download. This particular one is slightly out of sequence, but because I thought it was too awesome to wait I've posted it here early. It will included in the next D3 Tips and Tricks pdf so you can just download the pdf  and / or the examples from the downloads page:-)
--------------------------------------------------------

Recently Mike Bostock recommended 'Plunker' (http://plnkr.co/) as a tool for saving work online for collaboration and sharing. Although I had a quick look, I didn't quite 'get it' and although it looked like something that I should be interested in, I (foolishly) moved on to other things.

Quite frankly I should have persevered.

Plunker is awesome.

So what can it do for you?

Well, in short, this gives you a place to put your graphs on the web without the hassle of needing a web server as well as allowing others to view and collaborate! There are some limitations to hosting graphs in this environment, but there's no denying that for ease of use and visibility to the outside world, it's outstanding!
Time for an example. I'll try to go through the process of implementing the simple graph example on Plunker.
So it's as simple as going to http://plnkr.co/edit/
What you're seeing here is an area where you can place your entire HTML code. So let's replace the 11 lines of the place holder code with the simple graph example (just copy and paste it in there over the top of the current 11 lines);

Now, there are two important things we have to do before it will work.
  1. We need to tell he script where to find d3.js
  2. We need to make our data accessible
Helping the script find d3.js is nice and easy. Just replace this line in your plunk;
<script type="text/javascript" src="d3/d3.v3.js"></script>
...with this line...
<script src="http://d3js.org/d3.v3.min.js"></script>
That will allow your plunk to use the version of d3.js that is hosted on d3js.org (it uses the minimised version (which is why it has the 'min' in it), but never fear, it's still d3, just distilled to enhance the flavour :-)).
Making our data available is only slightly more difficult.

In experimenting with Plunker, I found that there appears to be something 'odd' about accessing the tab separated values that we have been using thus far (in the data.tsv file), however, D3 to the rescue! We can simply use Comma Separated Values (csv) instead (I've put a copy of the data.csv file in the examples and files download at d3noob.org).

So in preparation for this exercise, please edit your data.tsv file to have the tabs separating the values replaced by commas and rename it data.csv.

We will host our data.csv file on plunker as well and there is built in functionality to let us do it.
In the top left hand corner, beside the 'FILES' note, there is a '+NEW...' section. Clicking on this will allow you to create another file that will exist with your plunk for its use, so let's do that.

This will open a dialogue box that will ask you to name your new file.  
Enter the name data.csv.

Now another file has appeared under the 'Files' heading called data.csv. Click on it.
This now shows us a blank file called data.csv, so now open up your data.csv file in whatever editor you're using (I don't think a spreadsheet program is going to be a good idea since I doubt that it will maintain the information in a textual form as we're wanting it to do. So it's Geany for me). Copy the contents of your local data.csv file and past it into the new plunker data.csv file.

So now we have our data in there we need to tell our JavaScript where it is. So go back to the 'index.html' file (which is our simple graph code) and edit the line which finds the data.tsv file from this
d3.tsv("data/data.tsv", function(error, data) {
... to this ...
d3.csv("data.csv", function(error, data) {

Because we're using relative addressing, and plunker stores the files for the graphing script and the data side by side, we just removed the portion of the address that told our original code to look in the 'data' directory and told it to look in the current directory.

And that should be that!

Now if you look on the right hand side of the screen, there is a little eye icon. If you click on it, it opens up a preview window of your file in action and viola!


If the graph doesn't appear, go through the steps outlined above and just check that the edits are made correctly. Unfortunately I haven't found a nice mechanism for troubleshooting inside Plunker yet (not like using F12 on Chrome).

But wait! There's more!

If you now click on the 'Save' button at the top of the screen, you will get some new button options.
One of them is the orange one for showing off your work.
If you click on this, it will present you with several different options.
The first one is a link that will give others the option to collaborate on the script.

The second is a link that will allow others to preview the work; http://embed.plnkr.co/QSCkG8Rf2qFgrCqq7Vfn

The last will allow you to embed your graph in a separate web page somewhere. Which I've tested with blogger and seems to work really well! (see image below).
So, I'm impressed, Nice work by Plunker and it's creator Geoff Goodman.

------------------------------------------------------
The D3 Tips and Tricks document can be accessed from the downloads page of d3noob.org.



Friday, 28 December 2012

Actually drawing something with d3.js


The following post is a portion of the D3 Tips and Tricks document which it free to download from the main page. To use this post in context, consider it with the others in the blog or just download the pdf :-)
--------------------------------------------------------------------------
Up until now we have spent a lot of time defining, loading and setting up. Good news! We're about to finally draw something!

We jump lightly over some of the code that we have already explained and land on the part that draws the line.
svg.append("path")      // Add the valueline path.
        .attr("d", valueline(data));
This area occurs in the part of the code that has the data loaded and ready for action.

The svg.append("path") portion adds a new path element . A path element represents a shape that can be manipulated in lots of different ways (see more here: http://www.w3.org/TR/SVG/paths.html). In this case it inherits the 'path' styles from the CSS section and on the following line (.attr("d", valueline(data));) we add the attribute “d”.

This is an attributer that stands for 'path data' and sure enough the valueline(data) portion of the script passes the 'valueline' array (with its x and y coordinates) to the path element. This then creates a svg element which is a path going from one set of 'valueline' coordinates to another.

Then we get to draw in the axes;
svg.append("g")         // Add the X Axis
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")         // Add the Y Axis
        .attr("class", "y axis")
        .call(yAxis);
We have covered the formatting of the axis components earlier. So this part is actually just about getting those components drawn onto our canvas.

So both axes start by being appended to the “g” group. Then each has its own classes applied for styling via CSS. If you recall from earlier, they look a little like this;
.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}

Feel free to mess about with these to change the appearance of your axes.

On the x axis, we have a transform statement (.attr("transform", "translate(0," + height + ")")). If you recall, our point of origin for drawing is in the top left hand corner. Therefore if we want our x axis to be on the bottom of the graph, we need to move (transform) it to the bottom by a set amount. The set amount in this case is the height of the graph proper (height). So, for the point of demonstration we will remove the transform line and see what happens;
Yep, pretty much as anticipated.

The last part of the two sections of script ( .call(xAxis); and .call(yAxis); )call the x and y axis functions and initiate the drawing action.

The end of the beginning:

Well that's it. In theory, you should now be a complete D3 ninja. 

OK, perhaps a slight exaggeration. In fact there is a strong possibility that the information I have laid out here is at best borderline useful and at worst laden with evil practices and gross inaccuracies.

But look on the bright side. Irrespective of the nastiness of the way that any of it was accomplished or the inelegance of the code, if the picture drawn on the screen is pretty, you can walk away with a smile. :-).

This is the last portion of the explanation of our basic d3.js graph. There are of course more posts to come on additional 'stuff' you can accomplish, but (in theory) what we have laid out here (and probably more effectively in the D3 Tips and Tricks document (free to download from the front page)) will form a reasonable starting point.


Thursday, 27 December 2012

New Version of D3 Tips and Tricks (ver 0.2.a)

The latest version of D3 Tips and Tricks includes a minor version change which signifies that I have come to the the end of what I had anticipated to be the list of things I would describe using the simple line graph template.

That's not to say that this is the end of the document. Oh no...

There are a few other sections that I would like to include on specific things that I've had a play with. But more will follow there as they crop up.

The other change that I've made is to include a downloads page where I've put links to allow the downloading of some of the example files that I've been using. There's two versions of the simple line graph. One with little or no commenting and the other that is HEAVILY commented that people may find useful. Additionally, there is a zip file with the directory structure that I've been using for the examples and some of the example / data files as well. As time allows I will add to these.

As appears to be working so far, just click on the link on the left on the main page and you can download the pdf from there. or go to the downloads page.

Just a quick note as well... The process I am using to try and maintain a common point for downloading the pdf in drop box appears to cause it to fail to load the pdf when you go to download it the first time. DONT DESPAIR. Just reload and it appears. I will have to sort this out I know. I think I'll try to store it as a publicly accessible document in Google Drive in future releases.

Changelog:

How to format date / time axis labels with specific information
Changing a line graph into a scatterplot
Adding tooltips (with a smattering of transitions and events)

Wednesday, 26 December 2012

Adding the SVG canvas in d3.js


The following post is a portion of the D3 Tips and Tricks document which it free to download from the main page. To use this post in context, consider it with the others in the blog or just download the pdf :-)
--------------------------------------------------------------------------
As the title states, the next piece of script forms and adds the canvas that D3 will then use to draw on.

var svg = d3.select("body")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

So what exactly does that all mean?

Well D3 need to be able to have a space defined for it to draw things. And when you define the space it's going to use, you can also give the space you're going to use a name, attributes and positions within that space a designation.

In the example we're using here, we are 'appending' an SVG element (a canvas that we are going to draw things on) to the '<body>' element of the HTML page.

In human talk that means that on the web page and bounded by the <body> tag that we saw in the HTML part, we will have an area to draw on. That area will be 'width' plus the left and right margins wide and 'height' plus the top and bottom margins wide.

We also add an element 'g' that is referenced to the top left corner of the actual graph area on the canvas. 'g' is actually a grouping element in the sense that it is normally used for grouping together several related elements. So in this case those grouped elements will have a common reference.
(the image above is definitely not to scale, but I hope you get the general idea)

Interesting things to note about the code. The .attr(stuff in here) parts are attributes of the appended elements they are part of.

For instance;
.append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)

tells us that the 'svg' element has a "width" of width + margin.left + margin.right and the "height" of height + margin.top + margin.bottom.

Likewise...  
.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

tells us that the element "g" has been transformed by moving(translating) to the point margin.left, margin.top. Or to the top left of the graph space proper. This way when we tell something to be drawn on our canvas, we can use the reference point "g" to make sure everything is in the right place.

Tuesday, 25 December 2012

Adding data to a line function in d3.js

The following post is a portion of the D3 Tips and Tricks document which it free to download from the main page. To use this post in context, consider it with the others in the blog or just download the pdf :-)
--------------------------------------------------------------------------
We're getting towards the end of our journey through the script now. The next step is to get the information from the array 'data' and to place it in a new array that consists of a set of coordinated that correspond to the points we are going to plot.

var valueline = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });

Now I'm aware that the statement above may be somewhat ambiguous. You would be justified in thinking that we already had the data stored and ready to go. But that's not strictly correct.

What we have is data in a raw format, we have added pieces of code that will allow the data to be adjusted for scale and range to fit in the area that we want to draw, but we haven't actually taken our raw data and adjusted it for our desired coordinates. That's what the code above does.

The main function that gets used here is the d3.svg.line() function. This function uses assessor functions to store the appropriate information in the right area and in the case above they use the x and y assessors (that would be the bits that are '.x' and '.y'). The d3.svg.line() function is called a 'path generator' and this is an indication that it can carry our some pretty clever things on its own accord. But in essence its job is to assign a set of coordinates in a form that can be used to draw a line.

So each time this line function is called on, it will go through the data it is pointed to and it will assign coordinates to 'date' and 'close' pairs using the 'x' and 'y' functions that we set up earlier (which of course are responsible for scaling and setting the correct range / domain).

Of course, it doesn't get the data all by itself, we still need to actually call the valueline function with 'data' as the source to act on. But never fear, that's coming up soon.

Sunday, 23 December 2012

New Version of D3 Tips and Tricks (ver 0.1.g)


Merry Christmas Edition!

In general.

As well as a few tidy-ups, the following have been added in version 0.1.g of D3 Tips and Tricks.
As appears to be working so far, just click on the link on the left on the main page and you can download the pdf from there.

Changelog:

Updated filling an area under a line to include filling an area above a line.
Added a description of the predefined, named colours that can be used.
Added how to rotate text labels for an axis.
Added how to implement multiple axes.

Version 3.0 of D3 released

Mike recently announced the latest release of D3 as major version 3.0 with a large number of enhancements.
Chief among them appears to be a focus on transitions...

...and Jason Davies geographic projection manipulation.

The examples are fantastic and should be visited to get a feel for the different possibilities that they provide to an already awesome framework.
The examples used in the D3 Tips and Tricks document already use version 3 in the code, although they certainly don't utilize anything like the complexity available :-).

Friday, 21 December 2012

Setting up axes in d3.js

The following post is a portion of the D3 Tips and Tricks document which it free to download from the main page.
--------------------------------------------------------------------------

So we come to our next piece of code;
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);
I've included both the x and y axes because they carry out the formatting in very similar ways. And it's worth noting that this is not the point where the axes get drawn. That occurs later in the piece where the data.tsv file has been loaded as 'data'.

D3 has it's own axis component that aims to take the fuss out of setting up and displaying the axes. So it includes a number of configurable options.

Looking first at the x axis;
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);
The axis function is called with d3.svg.axis() and then the scale is set using the x values that we setup in the scales, ranges and domains section using .scale(x). Then a curious thing happens, we tell the graph to orientate itself to the bottom of the graph .orient("bottom"). Now if I tell you that "bottom" is the default setting, then you could be forgiven for thinking that technically, we don't need to specify this since it will go there anyway, but it does give us an opportunity to change it to to “top” to see what happens;
Well, I hope you didn't see that coming, because I didn't. So, it would transpire that what we're talking about there is the orientation of the values and ticks about the axis line itself. Ahh... Ok. So, useful if your x axis is at the top of your graph, but for this one, not so useful.

All right, he next part (.ticks(5)) sets the number of ticks on the axis. Hopefully you just did a quick count across the bottom of the previous graph and went “Yep, five ticks. Spot on”. Well done if you did, but there's a little bit of a sneaky trick up D3's sleeve with the number of ticks on a graph axis.

For instance, here's what the graph looks like when the .ticks(5) value is changed to .ticks(4).
Eh? Hang on. Isn't that some kind of mistake? There's still five ticks. Yep sure is. But wait... we can keep dropping the ticks value till we get to two and it will still be the same. At .ticks(2) though, we finally see a change.
How about that? At first glance that just doesn't seem right, then you have a bit of a think about it and you go “Hmm... When there were 5 ticks, they were separated by a week each, and that stayed that way till we got to a point where it could show a separation of a month.”.

So, what's going on here is that D3 is making a command decision for you as to how your ticks should be best displayed. This is great for simple graphs and indeed for the vast majority of graphs. And like all things D3, if you really need to do something bespoke and fancy, it'll let you if you know enough.

The following is the list of time intervals that D3 will consider when setting automatic ticks on a time based axis;
  • 1-, 5-, 15- and 30-second.
  • 1-, 5-, 15- and 30-minute.
  • 1-, 3-, 6- and 12-hour.
  • 1- and 2-day.
  • 1-week.
  • 1- and 3-month.
  • 1-year.
Just for giggles have a think about what value of ticks you will need to increase to until you get D3 to show more than five ticks.
Hopefully you won't sneak a glance at the following graph before you come up with the right answer.
Yikes! The answer is 10! And then when it does, the number of ticks is so great that they jumble all over each other. Not looking to good there. However, you could rotate the text (or perhaps slant it) and it could fit in (that must be the topic of a future how-to). You could also make the graph longer if you wanted, but of course that is probably going to create other layout problems. So think about your data and presentation as a single entity.

The code that formats the y axis is pretty similar;
var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

We can change the orientation to "right" if we want, but it won't be winning any beauty prizes.
Nope. Not a pretty sight.

So what about the umber of ticks? Well this scale is quite different to the x axis. Formatting the dates using logical separators (weeks, months) was tricky, but with standard numbers, it should be a little easier. In fact, there's a better than even chance that you've already had a look at the y axis and seen that there are 6 ticks there already when the script is asking for 5 :-)

And without too much fussing around, we can lower the tick number to 4 and we get a logical result.
But we need to raise the count to 10 before we get more than 6.