【D3.js 学习记录】——icicle冰锥图,sunburst光晕图数据可视化

冰锥图可视化

矩形冰锥图

d3.partition()官方文档

用来生成邻接图:一个节点链接树图的空间填充变体。与使用连线链接节点与父节点不同,在这个布局中节点会被绘制为一个区域(可以是弧也可以是矩形),并且其位置反应了其在层次结构中的相对位置。节点的尺寸被编码为一个可度量的维度,这个在节点-链接图中很难表示。

d3.partition().size()

返回一个函数,会把传入函数的数据划分成一个个区域,一般情况下使用方法为:

d3.json('./data/games.json').then( data => {
    root = d3.partition().size([height,width])(
        d3.hierarchy(data).sum(d => d.popularity)
        .sort((a,b) => {return b.popularity - a.popularity})
    );
});
代码理解
  • sum:每个节点的高度都由它的子节点的高度求和决定的。那么如何求和是由我们来告诉d3.js的。如:给非叶子结点的树形赋值为子节点
结果

在这里插入图片描述

做data join的时候,直接用 红框内的数据即可,绘制矩形和文本的时候都需要

  • x0,y0 : 矩形左上角的点
  • x1,y1 : 矩形右下角的点

绘制区域代码

//绘制矩形区域代码
g.selectAll('datarect').data(data.descendants()).join('rect')
    .attr('class', 'datarect' )
    .attr('fill', fill )
    .attr('x',d => d.y0 )
    .attr('y', d => d.x0)
    .attr('height', d => d.x1 - d.x0)
    .attr('width',  d => d.y1 -d.y0);

//绘制文本代码
g.selectAll('.datatext').data(data.descendants()).join('text') 
    .attr('class', 'datatext')
    .attr('x', d => (d.y0 + d.y1)/2)
    .attr('y', d => (d.x0 + d.x1)/2)
    .attr('text-anchor', 'middle')
    .text(d => d.data.name);

结果

在这里插入图片描述

问题

这种类型的冰锥图需要滑动网页查看,非常不方便,因此考虑将冰锥图掰成一圈,更加方便查看
在这里插入图片描述


Sunburst(光晕图)

数据预处理

  • 和冰锥图一样,依然是使用partition()这个接口,但是size应该要改变一下。
  • 画path时,设置d属性使用d3.arc()由于要画出环状的冰锥图,他用的是极坐标,需要注意的是,d3中默认的极坐标系0度是竖直向上的
  • Size放入的数组中包含两个元素,一个是角度 θ,一个是长度ρ
d3.json('./data/games.json').then( data => {
    root = d3.partition().size([2 * Math.PI, height / 1.6])
    (d3.hierarchy(data).sum(d => d.popularity)
     .sort((a, b) => b.popularity - a.popularity));

size为布局指定大小

  • 若是直角坐标系就传入width和height;
  • 若是极坐标系就传入θ和ρ的最大值;(注意,这里的θ用的是弧长,不是角度

绘制path(扇形区域)

const arc = d3.arc()
.startAngle(d => d.x0)
.endAngle(d => d.x1)
.innerRadius(d => d.y0)
.outerRadius(d => d.y1)
// .padAngle()

//startAngle:起始角度
//endAngle: 终止角度
//innerRadius:起始半径
//outerRadius:终止半径

color = d3.scaleOrdinal(d3.schemeCategory10)
g.selectAll('.datapath').data(data.descendants().filter(d => d.depth>0)).join('path')
    .attr('calss', 'datapath')
    .attr('d', arc )
    .attr('fill',fill )

绘制文本

g.selectAll('.datatext').data(data.descendants().filter(d => d.depth>0))
    .join('text')
    .attr('class', 'datatext')
    .attr('transform', d =>{
    let x = (d.x0 + d.x1) / 2 * 180 /Math.PI; 
    let y = (d.y0 + d.y1) / 2 ;
    //data中使用的是弧度制(x,y表示弧度),但是rotate()使用的是角度制,因此这里需要人为进行一步转换(*180/Math.PI)
    return `rotate(${x-90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`          
})
    .attr('text-anchor', 'middle')
    .text(d => d.data.name)

  • 注意:translate里面的函数执行时绝对有序的,rotate旋转的时候会连带着坐标轴一起旋转
  • text默认的0度是水平向右的,而d3中默认的0度是水平向上的,因此在rotate里面还是要减去90
  • 左半边的文本需要再转一下,让文字变正,因此在translate里面还要加上一个rotate,让左半边的文字旋转180度变正

矩形冰锥图icicle 可视化代码

<!DOCTYPE html>
<html>
  <head>
    <title>Icicle</title>
    <script src="./js/d3.min.js"></script>
    <meta charset="utf-8">
  </head>
  <body>
    <svg width="1000" height="3000" id="mainsvg" class="svgs" 
    style="display: block; margin: auto;"></svg>
    <script>
      const svg = d3.select('#mainsvg');
      const width = +svg.attr('width');
      const height = +svg.attr('height');
      const g = svg.append('g')
      //.attr('transform', `translate(${width/2}, ${height/2})`);
      let root;


      const fill = d => {
        if( d.depth == 0 ){
          //根节点
          return color(d.data.name);
        }
        while (d.depth >1 ){
          //不是第二层
          d = d.parent;
        }
        return color(d.data.name)
      };

      const render = function(data){
        color = d3.scaleOrdinal(d3.schemeCategory10);


        g.selectAll('datarect').data(data.descendants()).join('rect')
        .attr('class', 'datarect' )
        .attr('fill', fill )
        .attr('x',d => d.y0 )
        .attr('y', d => d.x0)
        .attr('height', d => d.x1 - d.x0)
        .attr('width',  d => d.y1 -d.y0);

        g.selectAll('.datatext').data(data.descendants()).join('text')   
        .attr('class', 'datatext')
        .attr('x', d => (d.y0 + d.y1)/2)
        .attr('y', d => (d.x0 + d.x1)/2)
        .attr('text-anchor', 'middle')
        .text(d => d.data.name);

      }


      d3.json('./data/games.json').then( data => {
        root = d3.partition().size([height,width])(
            d3.hierarchy(data).sum(d => d.popularity)
            .sort((a,b) => {return b.popularity - a.popularity})
          );

        render(root)


      });
 
      
    </script>
  </body>
</html>

可视化效果

在这里插入图片描述

光晕图Sunburst可视化代码(用到了极坐标轴)

<!DOCTYPE html>
<html>
  <head>
    <title>SunBurst</title>
    <script src="./js/d3.min.js"></script>
  </head>
  <body>
    <svg width="1600" height="940" id="mainsvg" class="svgs" 
    style="display: block; margin: auto;"></svg>
    <script>
      const svg = d3.select('#mainsvg');
      const width = +svg.attr('width');
      const height = +svg.attr('height');
      svg.attr("viewBox", [0, 0, width, height]);
      const g = svg.append('g')
      .attr('transform', `translate(${width/2}, ${height/2})`);
      let root;

      const arc = d3.arc()
      .startAngle(d => d.x0)
      .endAngle(d => d.x1)
      .innerRadius(d => d.y0)
      .outerRadius(d => d.y1)
      // .padAngle()

        const fill = d => { 
          while (d.depth > 1) 
            d = d.parent; 
          return color(d.data.name); 
        };

      const render = function(data){
        color = d3.scaleOrdinal(d3.schemeCategory10)

        g.selectAll('.datapath').data(data.descendants().filter(d => d.depth>0)).join('path')
        .attr('calss', 'datapath')
        .attr('d', arc )
        .attr('fill',fill )


        g.selectAll('.datatext').data(data.descendants().filter(d => d.depth>0))
        .join('text')
        .attr('class', 'datatext')
        .attr('transform', d =>{
          let x = (d.x0 + d.x1) / 2 * 180 /Math.PI; 
          let y = (d.y0 + d.y1) / 2 ;

//data中使用的是弧度制(x,y表示弧度),但是rotate()使用的是角度制,因此这里需要人为进行一步转换(*180/Math.PI)

            return `rotate(${x-90}) translate(${y},0) rotate(${x < 180 ? 0 : 180})`          
        })
        .attr('text-anchor', 'middle')
        .text(d => d.data.name)

        //注意:translate里面的函数执行时绝对有序的,rotate旋转的时候会连带着坐标轴一起旋转
        //text默认的0度是水平向右的,而d3中默认的0度是水平向上的,因此在rotate里面还是要减去90
        //左半边的文本需要再转一下,让文字变正,因此在translate里面还要加上一个rotate,让左半边的文字旋转180度变正

        }

 
      d3.json('./data/games.json').then( data => {
        root = d3.partition().size([2 * Math.PI, height / 1.6])
        (d3.hierarchy(data).sum(d => d.popularity)
        .sort((a, b) => b.popularity - a.popularity));

        console.log(root);
        render(root);
      });
      
    </script>
  </body>
</html>

可视化效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值