Viz.js 之二分图 BiPartite(二):多维比例数据展示

前言

Viz.js 系列的 Viz.js 之二分图 BiPartite (一),介绍了二分图相关的背景与理论概念。本文承上启下,介绍二分图在实际项目中的使用:多维度比例数据展示

维度比例数据展示

比例数据展示的基础流程如下:

下面结合流程,并附上相关的代码实现进行说明。

源数据准备

源数据是一个数组,数组元素是一个对象,每个元素都存放有主、次维度及目标值的数据。下面数据中,主维度是 group,次维度是 subgroup,目标值是 count

var data = [
  { group: 'A', subgroup: 'X', count: 2 },
  { group: 'A', subgroup: 'Y', count: 3 },
  { group: 'B', subgroup: 'X', count: 5 },
  { group: 'B', subgroup: 'Y', count: 8 },
  { group: 'C', subgroup: 'X', count: 2 },
  { group: 'C', subgroup: 'X', count: 9 },
  { group: 'D', subgroup: 'Z', count: 9 }
]

注意:目标值数据是用于进行比例计算的。

初始化 biPartite 实例

biPartite 实例初始化过程中,min 设置代表单个维度数据项显示区域的最小大小为 30,keyPrimary 设置代表在源数据中 group 项为主维度数据项,keySecondary 设置代表 subgroup 项为次维度数据项,value 为目标值,用于比例计算。

var bP = viz.biPartite()
      .min(30)
      .keyPrimary(d => d.group)
      .keySecondary(d => d.subgroup)
      .value(d => d.count)
      .data(data)

初始化 biPartite g 标签数据和鼠标事件监听

g 标签数据初始化

var bPg = d3.select("g").call(bP)
bPg.selectAll(".viz-biPartite-mainBar")
   .append("text")
   .attr("class", "perc")
   .text(d =>{ return d3.format('.0%')(d.percent)})

添加鼠标事件监听

mouseovermouseout 事件中,通过 d3 的选择器选中 classviz-biPartite-mainBar 的元素,设置百分比比例文字显示的格式。

function mouseover(d) {
  bP.mouseover(d)
  
  bPg.selectAll(".viz-biPartite-mainBar")
     .select(".perc")
     .text(d => { return d3.format(".0%")(d.percent) })
}
function mouseout(d) {
  bP.mouseout(d)
  
  bPg.selectAll(".viz-biPartite-mainBar")
     .select(".perc")
     .text(d => { return d3.format(".0%")(d.percent) })
}
bPg.selectAll(".viz-biPartite-mainBar")
   .on("mouseover", mouseover)
   .on("mouseout", mouseout)

初始化两侧文字

文字主要显示在单个维度数据项两侧,这里主要设置字体粗细,大小,偏移距离等。

function initLRSideText () {
  bPg.selectAll(".viz-biPartite-mainBar")
     .append("text")
     .attr("class", 'label')
     .attr("fontSize", '16px')
     .attr("font-weight", "bold")
     .attr("x", d => (d.part === "primary") ? -30 : 30)
     .attr("text-anchor", "start")
     .text(d => d.key)
}

效果

维度比例数据排序

按权重排序

在上述例子中,我们可以通过权重与自定义比较函数来对维度进行逆序:主维度逆序为 D -> C -> B -> A,次维度逆序为 Z -> X -> Y

设置权重

这里我们为主、次维度的可能情况分配一个权重值,用于自定义比较函数进行比较。

const sortMap = {
  group: {
    'A': 1,
    'B': 2,
    'C': 3,
    'D': 4
  },
  subGroup: {
    'X': 1,
    'Y': 2,
    'Z': 3
  }
}

自定义比较函数

compareGroupcompareSubGroup 均定义成降序函数,权重值高的维度项排在前面。

const sortFun = {
  compareGroup: (a, b) => sortMap['group'][b] - sortMap['group'][a],
  compareSubGroup: (a, b) => sortMap['subGroup'][b] - sortMap['subGroup'][a]
}

比较函数规则与 JavaScript 数组中的重排序函数规则是一致的。通过返回一个小于零、等于零或大于零的值来影响排序结果。

初始化 biPartite 实例

设置 sortPrimarysortSecondary 为自定义的比较函数。

var bP = viz.biPartite()
      .min(30)
      .keyPrimary(d => d.group)
      .sortPrimary(sortFun.compareGroup)
      .keySecondary(d => d.subgroup)
      .sortSecondary(sortFun.compareSubGroup)
      .value(d => d.count)
      .data(data)

效果

按权重排序

实战

假设有一组网站访问统计数据,格式如下:

"data": [
    {
      "sex": "男",
      "city": "深圳",
      "age": "31至45岁",
      "pv": 9200,
      "vv": 55
    }
    ...
]

在上述数据中,我们观测性别、年龄与城市 3 个维度,对应数据中的字段为 sexcityage,目标值为 pvvv,展示数据集中数据在各维度的分布情况。

下拉单选菜单

我们在模板中添加 3 个下拉单选菜单。用于主次维度与目标值选择。

<div class="select-layout">
    <select name="" id="left-select">
      <option value="age" selected>年龄</option>
      <option value="sex">性别</option>
      <option value="city">城市</option>
    </select>
    <select name="" id="mid-select">
      <option value="pv">指标:pv</option>
      <option value="vv">指标:vv</option>
    </select>
    <select name="" id="right-select">
      <option value="age">年龄</option>
      <option value="sex">性别</option>
      <option value="city" selected>城市</option>
    </select>
</div>

事件监听处理

主要监听 onchange 事件,获取当前下拉菜单项的值。

function baseOnSelectHandler(domId, originVar) {
    if (!domId) {
      return;
    }
    
    var selectNode = document.querySelector(domId);
    var options = selectNode.options;
    selectNode.onchange = () => {
      var idx = selectNode.selectedIndex;
      window[originVar] = options[idx].value;
      update();
    };
}
(function onLeftSelect() {
    baseOnSelectHandler("#left-select", "leftVal");
})();
(function onMidSelect() {
    baseOnSelectHandler("#mid-select", "midVal");
})();
(function onRightSelect() {
    baseOnSelectHandler("#right-select", "rightVal");
})();

重置 biPartite 实例与 g 标签数据

在事件监听处理中,将获取到的主次维度与目标值对 biPartite 实例进行重置,封装在一个 update 方法,实现下拉菜单与二分图显示联动。

function update() {
    bP = bP
      .keyPrimary(d => d[leftVal])
      .sortPrimary((a, b) => sortMap[leftVal][a] - sortMap[leftVal][b])
      .keySecondary(d => d[rightVal])
      .sortSecondary((a, b) => sortMap[rightVal][a] - sortMap[rightVal][b])
      .value(d => d[midVal]);
    bPg = d3.select("g").call(bP);
    bPg
      .selectAll(".viz-biPartite-mainBar")
      .append("text")
      .attr("class", "perc")
      .text(d => {
        return d3.format(".0%")(d.percent);
      });
    bPg
      .selectAll(".viz-biPartite-mainBar")
      .on("mouseover", mouseover)
      .on("mouseout", mouseout);
    initLRSideText();
  }

效果

多维比例数据展示

源码地址

源码链接: multi-dimension-biPartite-graph

参考

https://juejin.im/post/5e34f0b56fb9a02fbb76fad2

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论