Sunday, 13 January 2013

Selecting / filtering a subset of objects 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:-)
--------------------------------------------------------

OK, Imagine a scenario where you want to select (or should we say filter) a particular range of objects from a larger set for display in some way.

For example, what if we wanted to use our scatter plot example to show the line as normal, but we are particularly interested in the points where the values of the points fall below 400. And when it does we want them highlighted with a circle as we have done with all the point previously.

So that we end up with something that looks a little like this...
Err... Yes, for those among you who are of the observant persuasion, I have deliberately coloured them red as well (red for DANGER!).

This is a fairly simple example, but serves to illustrate the principle adequately.

From our simple scatter plot example we only need to add in two lines to the block of code that draws the circles as follows;
svg.selectAll("dot")        
        .data(data)                                     
    .enter().append("circle")                               
    .filter(function(d) { return d.close < 400 })        // <== This line
        .style("fill", "red")                            // <== and this one
        .attr("r", 3.5)                                     
        .attr("cx", function(d) { return x(d.date); })       
        .attr("cy", function(d) { return y(d.close); });
The first added line uses the '.filter' function to act on the data points and according to the arguments passed to it in this case, only return those where the value of d.close is less than 400 (return d.close < 400).
The second added line is our line that simply colours the circles red (.style("fill", "red")).

That's all there is to it. Pretty simple, but the filter function can be very powerful when used wisely.

I've placed a copy of the file for selecting / filtering into the downloads section on d3noob.org with the general examples as filter-selection.html.

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.

12 comments:

  1. The last code snippet is missing a semi colon on the filter line (I think). Thanks for this post though, I've just used it.

    ReplyDelete
    Replies
    1. Thanks for the observation. At first glance I thought the same thing (when you pointed it out). But I just tested it and it worked either with ({ return d.close < 400;}) or without ({ return d.close < 400 }) a semi colon. Weird. Did you test it and have it not work? If so perhaps it's a browser thing? I tested with Chrome under Windows. Thanks for the comment.

      Delete
    2. Well... missed semicolons are resolved by the JS interpreter.
      You've to read the Isaac Z. Schlueter post about it

      Delete
    3. This comment has been removed by the author.

      Delete
    4. Ahh... That makes sense. Would I be right in thinking that this could also be throwing up errors that Apache error log will collect?
      I'd also be interested in a link to the Isaac Z. Schlueter post you refereed to. I Gave him a googling and there's a lot of stuff he's done out there :-)

      Delete
  2. You're filtering after calling append, so you're actually creating circles for each data point. Since you're only setting required attributes on some of them, the others don't appear visually, but they're still there in the DOM. I would suggest moving the filter before the append, but it seems to give me errors. Weird.

    ReplyDelete
    Replies
    1. That's cool! I hadn't thought of that before and I see what you mean about the error. I think the only way around it would be to remove the points. I don't know if that would be appropriate for the tutorial, but you have made a great observation. One day I should do a section on using the developers tools for troubleshooting etc and this would be a great example of how they can be used. Cheers

      Delete
    2. I think you can add the filter inside the data call. e.g.:

      .data(data.filter(function(d) { return d.close < 400 }))
      .enter() ...

      Great site, thanks!

      Delete
  3. can we fill the color place of displaying dots

    ReplyDelete
    Replies
    1. I'm sorry, I'm not quite sure what you're asking. If you 're asking can we fill the displayed dots with another colour. then yes, that is nice and easy to do with the 'fill' statement in the post.

      Delete
  4. Is there a way to filter my data right after loading the csv or json? I'm working with canvas only using d3 for some other things but not calling .data, .enter or .append .... Any help would be great! Thanks

    ReplyDelete
    Replies
    1. There's a good chance I might not interpret your question correctly in the limited scope afforded by the comments section here. I would recommend that you post a question and include your code onto stack overflow and we can go from there :-)

      Delete