selection.filter() doesn't preserve indexes?

640 views
Skip to first unread message

John Whitley

unread,
Sep 30, 2011, 2:52:05 AM9/30/11
to d3-js
Hi all,

I've been diving into d3 for a new project, and have hit a bit of a
speedbump. Quoth the d3 wiki:

> Unlike the built-in array filter method, the returned selection
preserves the index of the original
> selection; thus, you can use the filter operator to apply other
operators to a subset of elements,
> without affecting the associated data or index.

As near as I can tell, this is not the case. I've put some sample
code up at https://gist.github.com/1252867. The console.log call in
the last statement (in attr("x1"...)) always returns serial values
starting from 0. Since I'm depending on a preserved index to
determine positioning of the current element, this poses a bit of a
problem.

This occurs in Firefox 7, Chrome 16 (Canary), and Safari 5.1, so I'm
fairly sure this isn't some browser-specific issue.

Am I missing something here? Also, in a prior attempt I'd various
combinations of inserting filter in the usual selection chain:

group.selectAll("...").data(...).enter().append()

I ended up stumped for some time with "object has no method filter"
errors, until I finally hit on the pattern in the gist by digging
through the examples and test code. The docs imply that filter is a
proper selection method, but this doesn't seem to be case either.

So what's the skinny on filter()? It seems like it's somehow not a
first-class selection method (or that other selection methods aren't
returning true selections.)

Thanks,
John





Mike Bostock

unread,
Sep 30, 2011, 11:52:18 AM9/30/11
to d3...@googlegroups.com
> Unlike the built-in array filter method, the returned selection preserves
> the index of the original selection; thus, you can use the filter operator
> to apply other operators to a subset of elements, without affecting the
> associated data or index.

Oops. That is indeed not the case. Looking at the code history, the
filter method has always behaved that way, though there is a
long-standing comment (question) mentioning this behavior:

// TODO preserve null elements to maintain index?

It looks like I was confused when I wrote the documentation for this
particular method.

> Since I'm depending on a preserved index to determine positioning of
> the current element, this poses a bit of a problem.

You can do the equivalent thing using select. So, if this was your filter:

selection.filter(function(d) { return d > 42; })

Instead say:

selection.select(function(d) { return d > 42 ? this : null; })

> So what's the skinny on filter()?  It seems like it's somehow not a
> first-class selection method (or that other selection methods aren't
> returning true selections.)

You likely encountered a different issue, which is that the enter
selection is not a first-class selection: it contains placeholder
nodes. The enter selection therefore does not support the full array
of operators, including filter.

https://github.com/mbostock/d3/blob/master/src/core/selection-enter.js

I expect we could add filter to the enter selection prototype, though.
But certainly not operators such as attr, and I don't think data would
make sense either.

Mike

John Whitley

unread,
Sep 30, 2011, 1:21:10 PM9/30/11
to d3...@googlegroups.com
Mike Bostock wrote:
>> Since I'm depending on a preserved index to determine positioning of
>> the current element, this poses a bit of a problem.
>
> You can do the equivalent thing using select. So, if this was your filter:
>
> selection.filter(function(d) { return d > 42; })
>
> Instead say:
>
> selection.select(function(d) { return d > 42 ? this : null; })


Brilliant, that worked swimmingly. I was going to suggest adding that to the wiki, but I just noted that you're way ahead of me on that front. This is a decent example of using a function with select().

> You likely encountered a different issue, which is that the enter
> selection is not a first-class selection: it contains placeholder
> nodes. The enter selection therefore does not support the full array
> of operators, including filter.

> [...]


> I expect we could add filter to the enter selection prototype, though.
> But certainly not operators such as attr, and I don't think data would
> make sense either.

The biggest issue in my mind would be to make the special cases clear in the docs. E.g. if a selection method returns nodes with a restricted signature, perhaps annotate that in the docs, ala "enter() returns placeholder nodes which support only the following selection methods: X, Y, Z. If you need to call other methods <example>."

Thanks for your work on d3, Mike. I haven't had this much fun getting into a new framework in ages!

-- John


Reply all
Reply to author
Forward
0 new messages