d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5

第三章 处理数据

         5.过滤数据

         想象一下你需要过滤d3选择的已经和可视化元素相关联的数据集,根据客户的输入数据信息显示或者隐藏某些可视化元素,D3提供了这种过滤方法来完成这种类型的数据可视化驱动,在本节中我们将展示这种方式是如何实现的。

         来看下面的代码。

         

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Data Filter</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>

<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, category) {
        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;
                });

        d3.select("body").selectAll("div.h-bar")
                .filter(function (d, i) { // <-E
                    return d.category == category;
                })
                .classed("selected", true);
    }

    render(data);

    function select(category) {
        render(data, category);
    }
</script>

<div class="control-group">
    <button onclick="select('Retail')">
        Retail
    </button>
    <button onclick="select('Gas')">
        Gas
    </button>
    <button onclick="select('Dining')">
        Dining
    </button>
    <button onclick="select()">
        Clear
    </button>
</div>

</body>

</html>

         上面的例子展示了通过用户对数据分类的选择,来对该数据对应的可视化元素进行高光显示。当我们选择Dinning按钮时上面代码显示的效果如下图:

          d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5_第1张图片

           在本例中,数据集是一个包含了消费费用和消费类别的个人消费信息记录,我们可以从代码标记的A处看到,在B、C、D处我们可以看到采用了前面讲过的D3用的enter-update-exit模式,来定义了一组水平的div元素与我们定义的数据集进行绑定。目前为止这些代码和前面例子中的并没有什么大的区别。接下来我们来看看E处

        d3.select("body").selectAll("div.h-bar")
                .filter(function (d, i) { // <-E
                    return d.category == category;
                })
                .classed("selected", true);

          d3 selection.filter方法以函数作为参数,该函数施加于所有的选择元素中,本例作为参数的方法有2个参数和一个隐藏的对象引用:

           d:当前对象绑定的数据元素。

            i:当前对象的索引。

           this:隐藏的对当前的dom对象的引用。

           d3 selection.filter方法期望参数方法返回布尔类型的值,如果返回的值为真,相应的元素会包含到filter方法的新的选择中,在本例中,filter方法返回符合用户选择的消费类,然后对对应于该类方法的可视化元素设置css属性,这种方式可以快速的过滤数据,并产生新的选择,允许用户对这些新选择做进一步的修改和操作。

           提示:

           d3 selection.filter方法对待其参数的返回值采用的是javascript的真假机制,也就是不是严格的布尔类型值,比如false、null、0、“”、undefined、NaN都被认为是false,其他的被认为是ture。


6.分类数据

           在很多情况下,有必要根据其绑定的数据对你的可视化元素进行分类,这样可以突出重点,直观的找出数据的不同的地方。在本节中我们将展示d3是如何实现这种效果的。

           打开编辑器,输入下面的代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Data Sort</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>

<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>

</body>

</html>

              本例继续使用前面例子用到的数据和结构,然后对数据进行分类排序,在这个例子中我们将对我们创建的div元素,根据其对应数据的进行分类和排序。我们对div进行宽度排序的效果如下所示:

d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5_第2张图片

            本例A、B、C、D处和前面并无差别,一旦框架打好,在E处我们选择所有的div,然后调用sort()方法进行分类和排序。本例中是sort()方法的参数是两个比较函数

 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;
    };

          比较函数接收两参数,返回-1,1,或者0 。如果返回的是-1,那么a就是在b的前面,如果返回的是1,那么a就在b的后面,如何返回的是0,说明a和b相当,他们2个的位置会随意放置 。sort()方法返回一个新的已经排好序的选择。可以对该选择进行进一步的操作。


7.从服务器载入数据

          一般情况下你很少会只使用静态的数据来进行可视化,数据可视化通常是依靠服务器程序生成的动态数据来进行可视化。正因如此,D3也设计了很多方便的工具来完成这些任务,在本节中我们将会看到,D3的数据如何被动态的加载,相应的可视化元素也动态的进行更新。

          本节中我们就要用到前面说过的服务器程序了,我本地安装的是wamp集成环境,这个比较简单,可以根据自己习惯来选择。

          那么我们再编写的代码文件,就要房子服务器的文件夹中,在wamp环境中末日是放在wamp安装目录的www文件夹里面

          首先在里面建一个json数据,命名为data.json

[
    {
        "expense": 15,
        "category": "Retail"
    },
    {
        "expense": 18,
        "category": "Gas"
    },
    {
        "expense": 10,
        "category": "Retail"
    },
    {
        "expense": 25,
        "category": "Gas"
    },
    {
        "expense": 66,
        "category": "Retail"
    },
    {
        "expense": 70,
        "category": "Gas"
    },
    {
        "expense": 44,
        "category": "Dining"
    },
    {
        "expense": 13,
        "category": "Dining"
    },
    {
        "expense": 20,
        "category": "Dining"
    },
    {
        "expense": 12,
        "category": "Retail"
    },
    {
        "expense": 15,
        "category": "Gas"
    }
]

            然后再新建一个文件,输入下面的代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Load JSON Data Feed</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 id="chart"></div>

<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) {
        d3.select("#chart").selectAll("div.h-bar") // <-B
                .data(data)
            .enter().append("div")
            .attr("class", "h-bar")
            .append("span");

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

        d3.select("#chart").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;
                });
    }

    render(data);

    function load(){ // <-E
        d3.json("data.json", function(error, json){ // <-F
            data = data.concat(json);  
            render(data);
        });
    }
</script>

<div class="control-group">
    <button onclick="load()">Load Data from JSON feed</button>
</div>

</body>

</html>

             本例中我们根据用户的选择来从服务器中加载数据,并完成可视化的更新,在服务器模式下浏览该文件。

d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5_第3张图片


             当点击load Data fom JSON feed按钮后的效果如下:

d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5_第4张图片


            在本例中我们在A处定义了一个静态数据,然后采用前面的框架实现可视化,当用户点击按钮时d3会从服务器载入data.json文件,d3会完成对文件的解析,然后调用render方法完成可视化。d3还支持对csv、tsv、txt、html、xml等类型文件的加载。当然这并不是 唯一可以加载数据的方式,D3对其他库的支持也是非常高,你也可以利用jquery或者zepto来创建ajax请求来加载数据。

你可能感兴趣的:(d3学习之(Data Visualization with d3.js Cookbook )(第三章)-5)