Sorting with data

In many cases, it is desirable to sort your visual elements according to the data they represent so that you can highlight the significance of different elements visually. In this recipe, we will explore how this can be achieved in D3.

Getting Ready

Open your local copy of the following file in your web browser:

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter3/data-sort.html

How to do it...

Let's see how data-driven sorting and further manipulation can be performed using D3. In this example, we will sort the bar chart we created in the previous recipe based on either expense (width) or category using user's input:

<script type="text/javascript">
    var data = [ // <-A
        {expense: 10, category: "Retail"},
        {expense: 15, category: "Gas"},
        {expense: 30, category: "Retail"},
        {expense: 50, category: "Dining"},
        {expense: 80, category: "Gas"},
        {expense: 65, category: "Retail"},
        {expense: 55, category: "Gas"},
        {expense: 30, category: "Dining"},
        {expense: 20, category: "Retail"},
        {expense: 10, category: "Dining"},
        {expense: 8, category: "Gas"}
    ];

    function render(data, comparator) {
        d3.select("body").selectAll("div.h-bar") // <-B
                .data(data)
            .enter().append("div")
                .attr("class", "h-bar")
                .append("span");

        d3.select("body").selectAll("div.h-bar") // <-C
                .data(data)
            .exit().remove();

        d3.select("body").selectAll("div.h-bar") // <-D
                .data(data)
            .attr("class", "h-bar")
            .style("width", function (d) {
                return (d.expense * 5) + "px";
            })
            .select("span")
                .text(function (d) {
                    return d.category;
                });

        if(comparator)
            d3.select("body")
                .selectAll("div.h-bar") 
                .sort(comparator); // <-E
    }

    var compareByExpense = function (a, b) {  // <-F
        return a.expense < b.expense?-1:1;
    };
    var compareByCategory = function (a, b) {  // <-G
        return a.category < b.category?-1:1;
    };

    render(data);

    function sort(comparator) {
        render(data, comparator);
    }
</script>

<div class="control-group">
    <button onclick="sort(compareByExpense)">
        Sort by Width
    </button>
    <button onclick="sort(compareByCategory)">
        Sort by Category
    </button>
    <button onclick="sort()">
        Clear
    </button>
</div>

This preceding code generates sorted horizontal bars as shown in the following screenshot:

How to do it...

Data-based Sorting

How it works...

In this recipe, we set up a simple row-based visualization (in line B, C, and D) of some simulated personal expense records containing two attributes: expense and category that are defined on line A. This is exactly the same as the previous recipe and quite similar to what we have done in the Binding object literals as data recipe. Once the basics are done, we then select all existing bars on line E and perform sorting using D3 selection.sort function:

d3.select("body")
    .selectAll("div.h-bar") 
    .sort(comparator); // <-E

The selection.sort function accepts a comparator function:

var compareByExpense = function (a, b) {  // <-F
    return a.expense < b.expense?-1:1;
};
var compareByCategory = function (a, b) {  // <-G
    return a.category < b.category?-1:1;
};

The comparator function receives two data elements a and b to compare, returning either a negative, positive, or zero value. If the value is negative, a will be placed before b; if positive, a will be placed after b; otherwise, a and b are considered equal and the order is arbitrary. The sort() function returns a new selection with all elements sorted in an order which is determined by the specified comparator function. The newly-returned selection can then be manipulated further to generate the desired visualization.

Tip

Because a and b are placed arbitrarily when they are equal, D3 selection.sort is not guaranteed to be stable, however, it is guaranteed to be consistent with your browser's built-in sort method on arrays.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset