Crossfilter.js用来过滤数据

来源:互联网 发布:java常用开发环境 编辑:程序博客网 时间:2024/05/14 03:15

这是一篇翻译  原文http://www.codeproject.com/Articles/693841/Making-Dashboards-with-Dc-js-Part-Using-Crossfil

Making Dashboards with Dc.js - Part 1: Using Crossfilter.js

原文是用来介绍dc.js的,我这里先来介绍crossfilter.js
  

Using the Code

Download the Crossfilter.js file from GitHub and include it in your HTML page. For these examples, I'm going to use the raw GitHub source for a reference.

首先从github上下载Crossfilter.js 文件并嵌入网页,如果是直接用github上面的代码的话就是一下引用。

<script type="text/javascript" src="https://rawgithub.com/NickQiZhu/dc.js/master/web/js/crossfilter.js"></script>

We'll first need some data. This data was pulled from the Crossfilter API documentation:

首先要有初始数据,crossfilter的API文档中是以下的数据:

var data = [  {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"}]; 

We'll make our Crossfilter instance.

生成crossfilter 实例。

 var ndx = crossfilter(data);
For our first example, we'll setup a filter using one of the integer columns. Say we want to get all the transactions with a total equal to 90. To do this, we need to setup a dimension.
对于我们的第一个例子,我们首先用一个整数列实现一个滤镜。我们想要所有交易信息中等于90的数据,为了做这个,我们需要安排一个维度。 
var totalDim = ndx.dimension(function(d) { return d.total; });   

Now we can start to filter it. If we wanted to find all the totals equal to 90, we can do the following:

我们能够开始过滤数据了。如果我们想要找到所有totals等于90的数据,就能像如下所示:

var total_90 = totalDim.filter(90); 

To see the result, we can print out the total_90 variable to the console.

为了看到结果,在console里面输出。(这里要注意,total_90本身是一个对象,需要特殊的函数来输出)

print_filter("total_90"); 

This prints out the following. I'll mark the webconsole data in black with white writing:

console的结果如下,print_filter这个函数下面会提到。

"total_90(6) = [{"date":"2011-11-14T17:22:59Z","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-14T16:58:03Z","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:48:46Z","quantity":2,"total":90,"tip":0,"type":"tab"},{"date":"2011-11-14T16:30:43Z","quantity":2,"total":90,"tip":0,"type":"tab"}]"  

### Tip ###

Since we want to be able to see if our filters are working correctly, I've created a small function to printout the data to the webconsole ("Tools" > "Web Developer" > "Web Console" in Firefox).

为了正确看到过滤效果,作者自己写了显示过滤效果的函数,粘贴在diamagnetic里面就好。

function print_filter(filter){var f=eval(filter);if (typeof(f.length) != "undefined") {}else{}if (typeof(f.top) != "undefined") {f=f.top(Infinity);}else{}if (typeof(f.dimension) != "undefined") {f=f.dimension(function(d) { return "";}).top(Infinity);}else{}console.log(filter+"("+f.length+") = "+JSON.stringify(f).replace("[","[\n\t").replace(/}\,/g,"},\n\t").replace("]","\n]"));} 

### End Tip ###

Each of these short hand filters has a long hand equivalent. For filter(90), it is the same as usingfilterExact(90):

filter(90),filterExact(90)效果是一样的

var total_90 = totalDim.filterExact(90); 
print_filter("total_90"); 
"total_90(6) = [{"date":"2011-11-14T17:22:59Z","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-14T16:58:03Z","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:48:46Z","quantity":2,"total":90,"tip":0,"type":"tab"},{"date":"2011-11-14T16:30:43Z","quantity":2,"total":90,"tip":0,"type":"tab"}]"   

If we want to filter a range from 90 to 100 inclusive, we'd put the parameter in brackets. Since we want to include100 in our filter, we'll need to have it go to 101. This is the same as total Dim.filterRange([90,101]);

如果想要范围的话,可以用filterRange([90,101])表示。

var total_90_101= totalDim.filter([90,101]); 
print_filter("total_90_101");  
"total_90_101(7) = [{"date":"2011-11-14T16:54:06Z","quantity":1,"total":100,"tip":0,"type":"cash"},{"date":"2011-11-14T17:22:59Z","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-14T16:58:03Z","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:48:46Z","quantity":2,"total":90,"tip":0,"type":"tab"},{"date":"2011-11-14T16:30:43Z","quantity":2,"total":90,"tip":0,"type":"tab"}]" 

You can even get a little more fancy like only grabbing items divisible by 3. This is the same astotalDim.filterFunction(function(d) { if (d%3===0)return d; } );

能被3整除的可以通过以下方式。

var total_3= totalDim.filter(function(d) { if (d%3===0) {return d;} } );  
print_filter("total_3"); 
"total_3(7) = [{"date":"2011-11-14T16:28:54Z","quantity":1,"total":300,"tip":200,"type":"visa"},{"date":"2011-11-14T17:22:59Z","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-14T16:58:03Z","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:48:46Z","quantity":2,"total":90,"tip":0,"type":"tab"},{"date":"2011-11-14T16:30:43Z","quantity":2,"total":90,"tip":0,"type":"tab"}]" 

That was pretty easy. Filtering on numbers is pretty straightforward unless you have an entry which is NaN. This will completely confuse crossfilter, so make sure there are no NaNs in your dataset.

Moving onto strings, if we wanted to find all the entries where people used visa, again, we need to first create a dimension, this time on the type, then we can do our filter.

如果数据有NaN,那么可能会出问题。

如果我们想要找到用visa用户的情况,那么我们就需要创造一个新的维度了。

var typeDim  = ndx.dimension(function(d) {return d.type;});
var visa_filter = typeDim.filter("visa"); 
print_filter("visa_filter"); 
"visa_filter(2) = [{"date":"2011-11-14T17:29:52Z","quantity":1,"total":200,"tip":100,"type":"visa"},{"date":"2011-11-14T16:28:54Z","quantity":1,"total":300,"tip":200,"type":"visa"}]"

If we wanted to do the same thing with cash, again, pretty easy.

var cash_filter = typeDim.filter("cash");  
print_filter("cash_filter");
"cash_filter(2) = [{"date":"2011-11-14T17:25:45Z","quantity":2,"total":200,"tip":0,"type":"cash"},{"date":"2011-11-14T16:54:06Z","quantity":1,"total":100,"tip":0,"type":"cash"}]"  

We can even sum up our total column for just the cash entries using the ReduceSum function. Ok, this is where it gets a little tricky. Previously, we were filtering on the dimension. You would think that you'd use the reduceSumfunction on the filtered data. That is not the case. If we do a ReduceSum on the filtered data through the groupfunction, it won't observe the current filter and will give you back the totals per type in key value format. This kindof makes sense and is pretty handy for dc.js, but not when you want to try to access the data for cash.

通过reduceSum可以对于cash的实例的total综合进行运算。typeDim是已经对tye进行维度提取的,然后再用group,reduceSum使用了total的数据。

var total = typeDim.group().reduceSum(function(d) {return d.total;});
 print_filter("total"); 
"total(3) = [{"key":"tab","value":920},{"key":"visa","value":500},{"key":"cash","value":300}]"

Instead to get the total for cash, you have to do a Groupall on the crossfilter object itself, which observes all filters; so that when we do a ReduceSum, we get the sum of the total column for the current filter.

(作者这里说的是cash的total,但是代码本身表示的是所有的total的总和,除非ndx本身是cash的filter)

var cash_total = ndx.groupAll().reduceSum(function(d) {return d.total;}).value() 
console.log("cash_total="+cash_total);  
"cash_total=300" 

So if the crossfilter object observes all filters, how come it didn't observer the visa filter when we decided to filter on cash? Well ... it's just kind of quirky. If you try to do a filter for cash and visa, it still has the cash filter applied.:

var cash_and_visa_filter = typeDim.filter(function(d) { if (d ==="visa" || d==="cash") {return d;} });  
print_filter("cash_and_visa_filter");
"cash_and_visa_filter(2) = [{"date":"2011-11-14T17:25:45Z","quantity":2,"total":200,"tip":0,"type":"cash"},{"date":"2011-11-14T16:54:06Z","quantity":1,"total":100,"tip":0,"type":"cash"}]" 

We need to first clear all filters and then it will work. It's good practise to always clear filters before starting another one.

首先要清除所有的过滤效果,在每次开始之前都要清楚原来的过滤效果。

typeDim.filterAll()
var cash_and_visa_filter = typeDim.filter(function(d) { if (d ==="visa" || d==="cash") {return d;} });
print_filter("cash_and_visa_filter");
"cash_and_visa_filter(4) = [{"date":"2011-11-14T17:29:52Z","quantity":1,"total":200,"tip":100,"type":"visa"},{"date":"2011-11-14T16:28:54Z","quantity":1,"total":300,"tip":200,"type":"visa"},{"date":"2011-11-14T17:25:45Z","quantity":2,"total":200,"tip":0,"type":"cash"},{"date":"2011-11-14T16:54:06Z","quantity":1,"total":100,"tip":0,"type":"cash"}]" 
0 0