![Data Visualization with D3.js Cookbook](https://wfqqreader-1252317822.image.myqcloud.com/cover/563/36705563/b_36705563.jpg)
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:
![](https://epubservercos.yuewen.com/0717C5/19470459808231506/epubprivate/OEBPS/Images/2162OS_03_09.jpg?sign=1739698459-9QO5n6e2UcKkgbvTK5z8YqfiBvtpULAz-0-06d28c93f9e2f955e8d8d5930a1af12c)
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.