官术网_书友最值得收藏!

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:

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.

主站蜘蛛池模板: 昭通市| 鹤壁市| 磐安县| 四子王旗| 南涧| 丹棱县| 郁南县| 亳州市| 嘉峪关市| 禄丰县| 西峡县| 临西县| 凤山县| 枝江市| 新绛县| 玉溪市| 巴林右旗| 弥渡县| 盐城市| 广安市| 克拉玛依市| 青阳县| 华安县| 定安县| 乌兰县| 项城市| 永城市| 光山县| 若羌县| 镇原县| 正宁县| 南部县| 西华县| 嵊州市| 沁水县| 华亭县| 汤阴县| 涞水县| 革吉县| 荔浦县| 嵊州市|