数据可视化Data-Driven Documents

来源:互联网 发布:桌面文件夹归类软件 编辑:程序博客网 时间:2024/05/21 03:16
http://alignedleft.com/tutorials/d3/
D3简介
        D3全称:Data-Driven Documents
        D3是一个很神奇的基于Javascript的在网页上实现数据可视化的工具。作者是原可视化工具Protovis开发小组的成员Mike Bostock,现Protovis已经不再更新,Mike Bostock将主要精力转向以Protovis为基础的D3,更好的支持大数据处理和动态交互。已发布到V2版本,作者也提供V3版本,但尚未正式发布。
        掌握D3的基础:
            1、熟悉 HTML,DOM,CSS;
            2、有那么一点点的编程经历;
            3、知道什么是 jQuery,至少要了解Javascript;
            4、愿意去学习CSV、SVG、JSON、正则表达式等知识点;
            5、为了更好的理解,可以补充一些XML、XHML、HTML5、AJAX等等,清楚其中的区别;
            6、你需要有热情,并愿意做出优秀的、交互式可视化图形。
        开发工具:不是必需的!
        基于D3的开发不需要特别的开发工具,用系统自带的记事本就可以(不推荐使用写字板),如果为了可视方便,可以使用Notepad++或者Editplus,推荐WebStorm。
        调试:Chrome 和 Firefox 都自带Javascript调试功能。
        为了本地开发方便,可以装个本地server。
简单的开始
准备工作
        参考项目目录:
        /
            d3/
                d3.v2.js
                d3.v2.min.js
            index.html
        其中d3.v2.min.js是压缩版,更小,推荐网站发布时使用。
        简单的布局:
        <html>
            <head>
                <title>D3 Test</title>
                <script type="text/javascript" src="d3/d3.v2.js"></script>
            </head>
            <body>
                <script type="text/javascript">
                    // D3代码可以从个区域开始,为了方便我们做个START标记。
                </script>
            </body>
        </html> 
        上例只是内嵌形式,也可以将D3代码写在单独的 .js 文件中。
添加元素
        我们在START区域内写入:
            d3.select("body").append("p").text("New paragraph!");
        结果看到我们没有写标签<p>,但是出现了一个段落。
        解析:
            d3代表D3对象;
            d3的select()方法通过使用CSS选择器的语法来选择DOM元素(如body),并且选择的是第一个匹配的元素,使用 selectAll() 可以返回所有匹配元素。
            append()方法是在所选择元素内的末尾加上元素(如p),也即追加;
            text()方法写入元素内容。
D3语法
        D3的语法被称为链语法( chain syntax ),通过添加链节点可以在一行代码内实现多个操作。如上例可以写作:
            d3.select("body")
                .append("p")
                .text("New paragraph!");
        结果是一样的。那么为了读写方便,推荐使用这种方式,除非需要压缩代码。
        由于一个方法的输出类型往往是后一个方法的输入类型,因此链中的方法是按顺序排列的。
数据绑定及其使用
数据绑定:
        数据绑定是为了给选择的元素附加一个数值,以便后面使用,根据这个数值的大小可以自由控制元素的呈现形式。
        START:
            var dataset = [ 5, 10, 15, 20, 25 ];
            d3.select("body").selectAll("p")
                .data(dataset)
                .enter()
                .append("p")
                .text("New paragraph!");
        绑定方法:selection.data()   data()参数是绑定的数据。
        有时候数据数量可能多于所选元素数量,这时候就需要使用 .enter()方法来检查数量是否相等,如果不等,enter()会创建一个新的元素占位符(placeholder),然后把占位符的引用提交给链的下一环节。
        .append()方法获取enter()方法创建的元素占位符后,将新的p元素添加到DOM。
        上述数据可以在Chrome Console输入console.log(d3.selectAll("p"))看到。
数据使用:
        把上述代码最后一行改为:
            .text(function(d) { return d; });
        上句匿名函数 function(d) 的参数d就是绑定的数值。具体的返回值,可以在匿名函数内写控制代码。
Drawing divs
        这一节通过设置div来生成bar,首先设置div的class:
            div.bar {
                display: inline-block;
                width: 20px;
                height: 75px;   /* We'll override this later */
                margin-right: 2px;    //设定bar的间隔
                background-color: teal;
            }
        数据绑定:
            var dataset = [ 5, 10, 15, 20, 25 ];
            d3.select("body").selectAll("div")
                .data(dataset)
                .enter()
                .append("div")
                .attr("class", "bar");
                .style("height", function(d) {
                    return 5*d + "px";
                });
        返回5个不同高度的bar。
        随机数据的生成:
            var dataset = [];                        //Initialize empty array
            for (var i = 0; i < 25; i++) {           //Loop 25 times
                var newNumber = Math.round(Math.random() * 30);  // 0-30
                dataset = dataset.concat(newNumber); //添加数组元素
            }
        Javascript的String和Array都有concat方法,分别连接字符串和添加数组元素。
Drawing SVGs
        使用append() 和attr()来画SVG:
        START:
            //Width and height 
    var w = 500;
    var h = 50;
            //Data
    var dataset = [ 5, 10, 15, 20, 25 ];
    //Create SVG element
            var svg = d3.select("body")
                        .append("svg")
.attr("width", w)
.attr("height", h);
            var circles = svg.selectAll("circle")
                                        .data(dataset)
               .enter()
               .append("circle");
            circles.attr("cx", function(d, i) {
        return (i * 50) + 25;
            })
                        .attr("cy", h/2)
                        .attr("r", function(d) {
                            return d;
                        })
                        .attr("fill", "yellow")
                        .attr("stroke", "orange")
                        .attr("stroke-width", function(d) {
                            return d/2;
                        });
数据类型
        D3的输入数据非常灵活。
        数组Array:使用[ ]包括,逗号隔开,for()循环常用。
        对象Objects:使用{ }包括,不同值对用逗号隔开。
            var fruit = {
                kind: "grape",
                color: "red",
                quantity: 12,
                tasty: true
            };
        引用单个值时使用点标记( dot notation),例如:fruit.kind 
        数组+对象(Arrays + Objects):可以灵活使用,互相包含,根据需求设定。但记住数组使用[ ],对象使用{ }。
        JSON:与Objects的区别是属性名称都用{ }包括起来:
            var jsonFruit = {
                "kind": "grape",
                "color": "red",
                "quantity": 12,
                "tasty": true
            };
        GeoJSON:用于存储地理信息数据,是JSON对象的格式化。GeoJSON对象也是JSON对象,所有的JSON对象都是Javascript对象。 
        GeoJSON 在地理空间上存储点坐标(经纬度坐标系),也可以在形状或其它空间特性上存储。经度在前,纬度在后。具体示例见JSON之GeoJSON。
D3数据格式化
        d3.format(specifier):通过指定说明符specifier返回一个新的格式化函数,这个新的格式化函数只能输入一个参数值,然后返回说明符specifier指定的格式。
        specifier形式:  [*sign*][0][*width*][,][.*precision*][*type*]
            sing:+ 表示正负数都可用新函数,- 表示只能负数用,空格只能用于正数。
            width:定义字段宽度。
            .*precision:参数指定精确到几位小数
            type: e(使用Javascript当中的Number.toExponential方法), g(Number.toPrecision), f(Number.toFixed), d(Number.toString), r(同f,但约等于设定的有效位), %(同f,但转成百分率形式), p(同r,但是转成%表示), s(同f,但附加一个单位符号)。
        示例:
            var zero = d3.format("04d");
            zero(2); // "0002"
            zero(123); // "0123"
        d3.round(x[, n]):将x约等于到包含n位小数的值。
        d3.requote(string):返回String的引用,使得String可以作为字符串面量嵌入到正则表达式中。
制作柱状图/条形图(使用一维数据)
        通过svg和通过div画柱状图的区别是:svg坐标原点在左上角,画自下而上的chart表需要坐标倒置(使用缩放功能更简单,见后文)。
        填充颜色: .attr("fill", "teal");
        Labels:添加标签。
        svg.selectAll("text")
                .data(dataset)
                .enter()
                .append("text")
                .text(function(d) {
                    return d;
                })
                .attr("text-anchor", "middle")
                .attr("x", function(d, i) {
                    return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
                })
                .attr("y", function(d) {
                    return h - (d * 4) + 14;
                })
                .attr("font-family", "sans-serif")
                .attr("font-size", "11px")
                .attr("fill", "white");
制作散点图(使用二维数据)
        示例:
        var dataset = [
                                [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
                                [410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
                               ];
        var svg = d3.select("body")
                            .append("svg")
                            .attr("width", w)
                            .attr("height", h);
        svg.selectAll("circle")
                .data(dataset)
                .enter()
                .append("circle")
                .attr("cx", function(d) {
                    return d[0];
                })
                .attr("cy", function(d) {
                    return d[1];
                })
                .attr("r", 5);
        上面的d是一个两个值的数组,分别是xy坐标。
小结
        通过上面简单的示例可以看出,D3的核心内容就是加载数据、创建元素、用数据驱动元素属性,到这里就可以理解D3是数据驱动文档的含义。

D3高级教程
Scales缩放
        由于数据直接当作图像px值来用,有时候尺寸、位置并不完全合适,需要使用缩放功能。d3自带scales方法 d3.scale,可以根据需要指定参数。缩放的概念类似于标准化。
        输入域(input domain)是指输入数据值的域。输出范围(output range)域是待定输出值的范围,通常就用来显示数据。
线性缩放
            var xscale = d3.scale.linear()
                                    .domain([100, 500])
                                    .range([10, 350]);
        然后就可以给xscale()指定参数,返回缩放后的值:
            xscale(100);  //Returns 10
        xscale()既是一个函数,又是一个带有自己方法的对象。
        通常要处理的数据比较多,domain需要使用min()方法和max()方法确定最小值和最大值。
        x轴缩放:
            var xScale = d3.scale.linear()
                     .domain([0, d3.max(dataset, function(d) { return d[0]; })])
                     .range([0, w]);
        y轴缩放:
            var yScale = d3.scale.linear()
                     .domain([0, d3.max(dataset, function(d) { return d[1]; })])
                     .range([0, h]);
        然后将d分别作为xScale和yScale的参数来进行缩放返回新值。
            .attr("cx", function(d) {
                return xScale(d[0]);
            })
            .attr("cy", function(d) {
                return yScale(d[1]);
            })
        缩放还有一个非常有用的功能就是解决SVG的坐标系问题:
            .range([h, 0]);
        添加一个边界变量可以避免图形跑到边界以外:
            var padding = 20;
            .range([padding, w - padding]);
            .range([h - padding, padding]);
        线性缩放的其它方法:
        d3.scale.linear() 还有一些其它很有用的方法:
        nice():自动将任何range()的参数向两边取简化值,避免参数有很长的小数。
        rangeRound():作为range()的替代,将所有的输出值约等于整数。
        clamp():如果一个新的输入数据输出后超出了边界,使用clamp(true)可以将超出边界的值显示在距离最近的边界。
其它缩放类型:
    数学缩放(线性缩放也是数学缩放)
            identity: identity缩放是线性缩放的特殊类型,实现 1:1 的缩放,其方法都是恒等函数,只在偶尔处理像素坐标时有用。
            quantize: quantize缩放是linear缩放的变体,输入的域是连续的,使用离散的range,输入数据被分割成不同的片段,也即是分类,如群体按设定的年龄段分类。
            quantile: 也是linear缩放的变体,无论输入数据什么分布,都会被映射成离散值。
        pow指数缩放: pow缩放与线性缩放相似,区别是pow缩放首先对输入数据进行指数变换,相当于 y = mx^k + b,其中k是.exponent()的指定参数,默认为1,所以默认情况下也是数值 1:1 的缩放。
            sqrt: sqrt缩放是pow缩放的特殊类型,默认是平方根缩放。
                d3.scale.pow().exponent(.5)
                通过exponent()方法指定指数。
        log对数缩放: log缩放与linear缩放相似,区别是log缩放首先对输入数据进行对数变换,相当于 y = m log(*x*) + b 。
        threshold缩放:阈值缩放与quantize缩放类似,不过允许将任意的子集映射到离散的range。
    Ordinal缩放:
        ordinal: 输入域是离散的,比如名字或类别。
        categorical colors: 输出颜色值。
Axes坐标轴
        axes用来和scales缩放协作以丰富图形的内容。axes可以创建SVG的元素,包括线、标签、小标记等等。
        axes的缩放参照前面缩放的xScale或yScale:
            var xAxis = d3.svg.axis()
                                    .scale(xScale)
                                    .orient("bottom");
                                    .ticks(5);
        然后调用xAxis函数在图中创建线条和标签,使用call()将上个链节点的selection作为其方法的应用对象:
            svg.append("g")    \\g不是必须的,只为产生一个标签方便链操作
                    .call(xAxis);
        坐标轴标尺的确定由ticks()方法实现,但其参数只是参考,D3会根据参考调整合适的标尺个数。
        tickFormat()方法更好的控制坐标轴显示,首先要用到d3.format()格式化方法。将刻度值转变成小数点后保留1位的百分率形式:
            var formatAsPercentage = d3.format(".1%");
            xAxis.tickFormat(formatAsPercentage);
加载外部文档
        d3.xhr(url[, mime], callback):使用XMLHttpRequest请求资源。
        d3.text(url[, mime], callback) :读取文本文件。
        d3.json(url, callback):读JSON文件。
        d3.html(url, callback):读HTML文件。
        d3.xml(url[, mime], callback):读xml文件。
        d3.csv(url, callback):读逗号分隔的.csv文件。
        d3.tsv(url, callback):读tab键分隔的tsv文件。

0 0