1

I'm working with D3.js and trying to sort my bars in ascending/descending order when a button is clicked. But I'm having issues having the sortBars function return the correct value from my object.

var sortOrder = false;
var sortBars = function() {
sortOrder = !sortOrder;
svg.selectAll("rect")
    .sort(function(a, b) {
        if (sortOrder) {
            return d3.ascending(a, b);
        } else {
            return d3.descending(a, b);
        }
    })
    .transition()
    .delay(function(d, i) {
        return i * 50;
    })
    .duration(1000)
    .attr("x", function(d, i) {
        return xScale(i);
    });
}; 

When it returns xScale(i), I know it's not referencing my dataset appropriately. I've tried placing it as i.value (which is what I have it named as in my dataset). I know this isn't correct, but when I change it to that, I at least get the bars to move. How would I access the correct datum?

I've developed a JSFiddle for this. Feel free to play around with it. Currently, the Sort button won't have any effect (as the function is not correctly accessing the data yet).

2 Answers 2

1

Your code was almost good, there are just two details:

The comparator function must return positive, negative or zero. In your code you are comparing data items, not their values:

function sortItems(a, b) {
   if (sortOrder) { return a.value - b.value; }
   return b.value - a.value;
}

svg.selectAll('rect')
.sort(sortItems)
// update the attributes

The sortBars method wasn't working. I prefer to bind the event using d3:

// Bind the event 'onclick' to the sortBars functions
d3.select('#sort').on('click', sortBars);

I forked your jsFiddle and adapted to make it work: http://jsfiddle.net/pnavarrc/3HL4a/4/

References

Sign up to request clarification or add additional context in comments.

1 Comment

That almost seems too simple! haha. I think I like it better than my if/else attempt. I was assuming that my issue was with the xScale returning the index, I didn't even think that it would be with the sort() itself... which is more logical now that I think about it. Also see that you updated my Text - hadn't done that yet. Thanks!
1

I think you are pretty close. The xscale should be using i - which here is the position of the datum in the list (not the datum which is in d). However your sort is trying to sort the data objects, not the values. Try this:

.sort(function(a, b) {
    if (sortOrder) {
        return d3.ascending(a.value, b.value);
    } else {
        return d3.descending(a.value, b.value);
    }
})

I think with two objects it is undefined which one is bigger. And the ascending and descending functions do not take accessors.

1 Comment

Of course, the issue is not adding value in sort(). Great solution. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.