zoukankan      html  css  js  c++  java
  • D3.js系列——布局:弦图和集群图/树状图

    一、弦图

    1、弦图是什么

      弦图(Chord),主要用于表示两个节点之间的联系的图表。两点之间的连线,表示谁和谁具有联系。

    2、数据

      初始数据为:

    var city_name = [ "北京" , "上海" , "广州" , "深圳" , "香港"  ];
    var population = [
              [ 1000,  3045  , 4567 , 1234 , 3714 ],
              [ 3214,  2000  , 2060 , 124  , 3234 ],
              [ 8761,  6545  , 3000 , 8045 , 647  ],
              [ 3211,  1067  , 3214 , 4000  , 1006 ],
              [ 2146,  1034  , 6745 , 4764  , 5000 ]
            ];

      数据是一些城市名和一些数字,这些数字表示城市人口的来源。其意思如下:

      北京 上海
    北京 1000 3045
    上海 3214 2000

      左边第一列是被统计人口的城市,上边第一行是被统计的来源城市,即:

      北京市的人口有 1000 个人来自本地,有 3045 人是来自上海的移民,总人口为 1000 + 3045。

      上海市的人口有 2000 个人来自本地,有 3214 人是来自北京的移民,总人口为 3214 + 2000。

      好了!!!对于这样一组数据,怎么进行可视化。

    3、布局(数据转换)

      弦图的布局如下:

     var chord_layout = d3.layout.chord()
          .padding(0.03) //节点之间的间隔
          .sortSubgroups(d3.descending) //排序
          .matrix(population); //输入矩阵

      然后,应用此布局转换数据。

    var groups = chord_layout.groups();
    var chords = chord_layout.chords();
     
    console.log( groups );
    console.log( chords );

      population 经过转换后,实际上分成了两部分:groups 和 chords。前者是节点,后者是连线,也就是。chords 就是上图中的连线。chords 里面又分为 source 和 target ,也就是连线的两端。

      在控制台输出一下节点和连线,看看得到了怎样的数据。

      节点:

      连线(弦):

    4、绘制节点

       先定义相关变量,很熟悉了

     var width = 600;
     var height = 600;
     var innerRadius = width/2 * 0.7;
     var outerRadius = innerRadius * 1.1;
     
     var color20 = d3.scale.category20();
     
     var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(" + width/2 + "," + height/2 + ")")

      绘制节点(即分组,有多少个城市画多少个弧形),及绘制城市名称

    var outer_arc = d3.svg.arc()   //获取圆弧生成器的路径值
        .innerRadius(innerRadius)
        .outerRadius(outerRadius);
     
    var g_outer = svg.append("g"); //添加分组
     
    g_outer.selectAll("path")
        .data(groups)
        .enter()
        .append("path")
        .style("fill", function(d) { return color20(d.index); })
        .style("stroke", function(d) { return color20(d.index); })
        .attr("d", outer_arc );  //绑定路径的属性值
     
    g_outer.selectAll("text")
        .data(groups)
        .enter()
        .append("text")
        .each( function(d,i) { 
           d.angle = (d.startAngle + d.endAngle) / 2; 
           d.name = city_name[i];
        })
        .attr("dy",".35em")
        .attr("transform", function(d){
           return "rotate(" + ( d.angle * 180 / Math.PI ) + ")" +
           "translate(0,"+ -1.0*(outerRadius+10) +")" +
           ( ( d.angle > Math.PI*3/4 && d.angle < Math.PI*5/4 ) ? "rotate(180)" : "");
         })
        .text(function(d){
           return d.name;
        });

      节点位于弦图的外部。节点数组 groups 的每一项,都有起始角度和终止角度,因此节点其实是用弧形来表示的,这与饼状图类似。

      然后就是节点的文字(即城市名称),有两个地方要特别注意。

      each():表示对任何一个绑定数据的元素,都执行后面的无名函数 function(d,i) ,函数体里做两件事:

    • 计算起始角度和终止角度的平均值,赋值给 d.angle 。
    • 将 city_name[i] 城市名称赋值给 d.name 。

      transform 的参数:用 translate 进行坐标变换时,要注意顺序: rotate -> translate(先旋转再平移)。 此外,

    ( ( d.angle > Math.PI*3/4 && d.angle < Math.PI*5/4 ) ? "rotate(180)" : "")

      意思是,当角度在 135° 到 225° 之间时,旋转 180°。不这么做的话,下方的文字是倒的。

    5、绘制连线(弦)

      绘制连线(即所有城市人口的来源,即有 5 * 5 = 25 条弧)

    var inner_chord = d3.svg.chord()
        .radius(innerRadius);
     
    svg.append("g")
        .attr("class", "chord")
        .selectAll("path")
        .data(chords)
        .enter()
        .append("path")
        .attr("d", inner_chord )  //path值
        .style("fill", function(d) { return color20(d.source.index); })
        .style("opacity", 1)
        .on("mouseover",function(d,i){
            d3.select(this)
              .style("fill","yellow");
        })
        .on("mouseout",function(d,i) { 
            d3.select(this)
              .transition()
              .duration(1000)
              .style("fill",color20(d.source.index));
        });

      SVG 中没有现成的弦元素(例如圆有 <circle>,但是弦却没有 <chord>),需要用路径元素 <path> 来制作。至于路径值是什么呢?我们不需要手动计算,D3 提供了 d3.svg.chord() ,只需要将弦的对象传递给它,即可得到路径值

      上面还有几句关于交互式操作的代码: mouseover 和 mouseout 。

    二、集群图

      集群图,是一种用于表示包含与被包含关系的图表。

    1、数据

      初始数据先写在一个 JSON 文件中,再用 D3 来读取。现有数据如下:

    {
    "name":"中国",
    "children":
    [
        { 
          "name":"浙江" , 
          "children":
          [
                {"name":"杭州" },
                {"name":"宁波" },
                {"name":"温州" },
                {"name":"绍兴" }
          ] 
        },
        
        { 
            "name":"广西" , 
            "children":
            [
                {"name":"桂林"},
                {"name":"南宁"},
                {"name":"柳州"},
                {"name":"防城港"}
            ] 
        },
        
        { 
            "name":"黑龙江",
            "children":
            [
                {"name":"哈尔滨"},
                {"name":"齐齐哈尔"},
                {"name":"牡丹江"},
                {"name":"大庆"}
            ] 
        },
        
        { 
            "name":"新疆" , 
            "children":
            [
                {"name":"乌鲁木齐"},
                {"name":"克拉玛依"},
                {"name":"吐鲁番"},
                {"name":"哈密"}
            ]
        }
    ]
    }

      这段数据表示:“中国 – 省份名 – 城市名”的包含于被包含关系。

    2、布局(数据转换)

      定义一个集群图布局:

    var cluster = d3.layout.cluster()
                     .size([width, height - 200]);

      布局保存在变量 cluster 中,变量 cluster 可用于转换数据。

      size() 设定尺寸,即转换后的各节点的坐标在哪一个范围内。

      接下来,转换数据:

    d3.json("city.json", function(error, root) {
      var nodes = cluster.nodes(root);
      var links = cluster.links(nodes);
      
      console.log(nodes);
      console.log(links);
    }

      d3.json() 是用来读取 JSON 文件的。要注意,d3.json() 不能读取本地文件。例如,将 html 文件与 json 文件放到本地同一目录,打开 html 文件是不能顺利读取的。需要搭建一个网络服务器来使用它,可用 Apache 搭建一个简单的服务器。否则,浏览器(Chrome)的控制台中,会出现以下错误:XMLHttpRequest cannot load file:///D:/*******/city.json. Cross origin requests are only supported for HTTP.

      经过测试,Firefox 可以直接读取本地文件,无需搭服务器,其他大多数浏览器不行。建议搭建服务器进行测试,这是正确的做法。

      d3.json() 函数后面跟一个无名函数 function(error) ,参数 root 是读入的数据。后两行代码调用 cluster 转换数据,保存到变量 nodes 和 links 中。然后输出转换后的数据,结果如下图所示:

      转换后的顶点数据(nodes):

      转换后的连接线数据(links):

      nodes 中有各个节点的子节点(children)、深度(depth)、名称(name)、位置(x,y)信息,其中名称(name)是 json 文件中就有的属性。

      links 中有连线两端( source , target )的节点信息。

    3、绘制

      D3 已经基本上为我们准备好了绘制的函数:d3.svg.diagonal() 。这是一个对角线生成器,只需要输入两个顶点坐标,即可生成一条贝塞尔曲线

      创建一个对角线生成器:

    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });

      projection() 是一个点变换器,默认是 [ d.x , d.y ],即保持原坐标不变,如果写成 [ d.y , d.x ] ,即是说对任意输入的顶点,都交换 x 和 y 坐标

      绘制连线时,使用方法如下:

    var link = svg.selectAll(".link")
          .data(links)
          .enter()
          .append("path")
          .attr("class", "link")
          .attr("d", diagonal);   //使用对角线生成器path值

      绘制节点时,还是用 <svg> 中的 <circle> 来绘制。

      //获取所有节点元素
      var node = svg.selectAll(".node")
          .data(nodes)
          .enter()
          .append("g")
          .attr("class", "node")
          .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
      //节点元素绘制圆
      node.append("circle")
          .attr("r", 4.5);
      //添加文本
      node.append("text")
          .attr("dx", function(d) { return d.children ? -8 : 8; })
          .attr("dy", 3)
          .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
          .text(function(d) { return d.name; });

    三、树状图

      树状图( Tree )用于表示层级、上下级、包含与被包含关系,其布局的用法与集群图几乎完全相同。

  • 相关阅读:
    Java SSL证书的安装
    zookeeper集群配置
    ERROR org.apache.zookeeper.ClientCnxn:532
    线程池c3p0和dbcp2的配置初始化实例
    SIP/2.0 403 Forbidden(Invalid domain in From: header)
    OkHttp实现文件上传进度
    Http 缓存机制
    Cookie、Session 和 Token区别
    RecyclerView-- 侧滑删除和拖动排序
    RecyclerView--添加头部和底部
  • 原文地址:https://www.cnblogs.com/goloving/p/8612061.html
Copyright © 2011-2022 走看看