第三章 处理数据
4.处理数组
我们大多数的数据都是以数组形式存储的,我们会花费大量的工作在格式化和重组数组的数据上,为此D3为我们提供了丰富的数组操作方法,使我们的工作简单化。在本节我们将展示最常用和实用的D3数组操作方法。
先来看下面的代码:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Working with Array</title> <link rel="stylesheet" type="text/css" href="styles.css"/> <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script> </head> <body> <div class="code">var array = [3, 2, 11, 7, 6, 4, 10, 8, 15]</div> <div>d3.min => <span id="min"></span></div> <div>d3.max => <span id="max"></span></div> <div>d3.extent => <span id="extent"></span></div> <div>d3.sum => <span id="sum"></span></div> <div>d3.median => <span id="median"></span></div> <div>d3.mean => <span id="mean"></span></div> <div>array.sort(d3.ascending) => <span id="asc"></span></div> <div>array.sort(d3.descending) => <span id="desc"></span></div> <div>d3.quantile(array.sort(d3.ascending), 0.25) => <span id="quantile"></span></div> <div>d3.bisect(array.sort(d3.ascending), 6) => <span id="bisect"></span></div> <div class="code"> <pre> var records = [ {date: "2011-11-14T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"}, {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"}, {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"}, {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0, type: "cash"}, {date: "2011-11-14T16:58:03Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90, tip: 0, type: "tab"}, {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0, type: "cash"}, {date: "2011-11-14T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"} ]; d3.nest() .key(function(d){return d.type;}) .key(function(d){return d.tip;}) .entries(records) => </pre> </div> <div> <pre id="nest"></pre> </div> <script type="text/javascript"> var array = [3, 2, 11, 7, 6, 4, 10, 8, 15]; d3.select("#min").text(d3.min(array)); d3.select("#max").text(d3.max(array)); d3.select("#extent").text(d3.extent(array)); d3.select("#sum").text(d3.sum(array)); d3.select("#median").text(d3.median(array)); d3.select("#mean").text(d3.mean(array)); d3.select("#asc").text(array.sort(d3.ascending)); d3.select("#desc").text(array.sort(d3.descending)); d3.select("#quantile").text( d3.quantile(array.sort(d3.ascending), 0.25) ); d3.select("#bisect").text( d3.bisect(array.sort(d3.ascending), 6) ); var records = [ {quantity: 2, total: 190, tip: 100, type: "tab"}, {quantity: 2, total: 190, tip: 100, type: "tab"}, {quantity: 1, total: 300, tip: 200, type: "visa"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 1, total: 100, tip: 0, type: "cash"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 2, total: 90, tip: 0, type: "tab"}, {quantity: 2, total: 200, tip: 0, type: "cash"}, {quantity: 1, total: 200, tip: 100, type: "visa"} ]; var nest = d3.nest() .key(function (d) { // <- A return d.type; }) .key(function (d) { // <- B return d.tip; }) .entries(records); // <- C d3.select("#nest").html(printNest(nest, "")); function printNest(nest, out, i) { if(i === undefined) i = 0; var tab = ""; for(var j = 0; j < i; ++j) tab += " "; nest.forEach(function (e) { if (e.key) out += tab + e.key + "<br>"; else out += tab + printObject(e) + "<br>"; if (e.values) out = printNest(e.values, out, ++i); else return out; }); return out; } function printObject(obj) { var s = "{"; for (var f in obj) { s += f + ": " + obj[f] + ", "; } s += "}"; return s; } </script> </body> </html>
以上的代码展示了D3所提供的最常用也是最有效的对数组的操作,在浏览器中运行的输出结果如下:
我们看看是如何工作的,D3提供了多种公共方法来帮助我们处理javascript数组,他们中的大多数是非常直观和直接的,然而,在本节中我们还是要简短的讨论一下他们的内在的东西。
我们看上面的代码,首先给了我们一个数组var array = [3, 2, 11, 7, 6, 4, 10, 8, 15];
d3.min(array)。d3.min这个方法用来获取数组中最小的元素,在本例中为2.
d3.max(array)。d3.max这个方法用来获取数组中最大的元素,在本例中为15.
d3.extent(array)。d3.extent这个方法返回数组中的最大值和最小值,本例中为2,15.
d3.sum(array)。d3.sum这个方法返回数组中所有元素的和,本例中为66.
d3.median(array)。d3.median这个方法返回数组中按大小顺序在中间的那个,本例中为7.
d3.mean(array)。 d3.mean这个方法返回数组中所有元素的平均值,本例为7.33.
array.sort(d3.ascending)/array.sort(d3.descending)。d3.ascending /d3.descending这个两个方法是D3内建的计算方法,可以用来对数组进行排序:
d3. ascending = function( a, b) { return a < b ? -1 : a > b ? 1 : 0;} 升序
d3. descending = function( a, b) { return b < a ? -1 : b > a ? 1 : 0;} 降序
d3.quantile(array.sort(d3.ascending), 0.25)。d3.quantile这个方法是计算已经升序排列的数组的分位数,本例中分位数为0.25的是4.
d3.bisect(array.sort(d3.ascending), 6)。d3.bisect这个方法可以获取已经排序数组中某个元素右边的元素,本例中6右边的为4.
d3.nest()方法可以用来建立一套算法,将一个平面阵列为基础的数据结构转变成一个分层嵌套结构,这种结构特别适合某些可视化项目,d3.nest()可以被看成是利用key方法链接到nest像我们在A处和B处看到的那样。
var nest = d3.nest()
.key(function (d) { // <- A
return d.type;
})
.key(function (d) { // <- B
return d.tip;
})
.entries(records); // <- C
多种key方法可以产生多层的嵌套,在本例中使用了2层,首先是type的值,然后是tip的值,最后展示的结果就是:
最后在C处entries方法用来支持平面阵列为基础的数据结构。