Monday, 14 January 2013

Select items with an IF statement in d3.js

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:-)
--------------------------------------------------------

The filtering – selection section above is a good way to adapt what you see on a graph, but so is a more familiar friend the 'if' statement.

An if statement will act to carry out a task in a particular way dependent on a condition that you specify.
Here's an example, what if we wanted to show our scatter plot as normal, but all those with a 'close' value less than 400 should be coloured red. Sound familiar? Yes, I know it's similar to the example above, with the subtle difference that it is leaving the circles above 400 in place (more on that to follow).

So, starting with the simple scatter plot example all we have to do is include the if statement in the block of code that draws the circles. Here's the entire block with the additions highlighted;
svg.selectAll("dot")    
        .data(data)                                     
    .enter().append("circle")                               
        .attr("r", 3.5)     
        .style("fill", function(d) {            // <== Add these
            if (d.close <= 400) {return "red"}  // <== Add these
            else    { return "black" }          // <== Add these
        ;})                                     // <== Add these
        .attr("cx", function(d) { return x(d.date); })       
        .attr("cy", function(d) { return y(d.close); });    
Our first added line introduces the style modifier and the rest of the code acts to provide a return for the 'fill' attribute.

The second line introduces our if statement. They're all pretty easy to follow between languages. Just look out for maintaining the correct syntax and you should be fine. In this case we're asking if the value of d.close is less than or equal to 400 and if it is it will return the “red” statement for our fill.

The third line covers our rear and make sure that if the colour isn't going to be red, it's going to be black. The last line just closes the style and function statements.

The result?
Aww..... nice.

I've placed a copy of the file that uses the if statement into the downloads section on d3noob.org with the general examples as if-statement.html.

Could it be any cooler? I'm glad you asked.

What if we wanted to have all the points where close was less than 400 red and all those where close was greater than 620 green? Oh yeah! Now we're talking.

So with one small change to the if statement;
.style("fill", function(d) {        
            if (d.close <= 400) {return "red"}  
            else if (d.close >= 620) {return "lawngreen"} // <== Right here 
            else { return "black" }             
        ;}) 
Check it out...
Nice.

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.

5 comments:

  1. Is there a shorthand existing like if d.close == undefined return d.close else return 1 ?

    ReplyDelete
    Replies
    1. Yeah, there are quite a few shorthand techniques in JavaScript. There's a good page here (http://www.sitepoint.com/shorthand-javascript-techniques/) that has some great examples.
      For the code above I really wanted to leave it long hand since it's aimed at people with less experience (like me :-)). Sometimes the shorthand versions can be a bit difficult to read.

      Delete
  2. I know that I can add a title tag to the circle by inserting
    .append("svg:title").text(function(d) {
    return (d.title_text);
    })
    But only some of my data points have an element d.title_text.
    How do I write it so that only those circles get a title tag? With the code above hey all get one, it is just empty if no text is provided,

    ReplyDelete
    Replies
    1. Hmm... (and please bear in mind that this is untested);
      if (d.title_test) {return "d.title_test"}
      else { return "" }

      Delete