矩形树图

矩形树图的简介

矩形树图由马里兰大学教授Ben Shneiderman于上个世纪90年代提出,起初是为了找到一种有效了解磁盘空间使用情况的方法。 矩形树图适合展现具有层级关系的数据,能够直观体现同级之间的比较。一个Tree状结构转化为平面空间矩形的状态,就像一张地图,指引我们发现探索数据背后的故事。

矩形树图采用矩形表示层次结构里的节点,父子节点之间的层次关系用矩形之间的相互嵌套隐喻来表达。从根节点开始,屏幕空间根据相应的子节点数目被分为多个矩形,矩形的面积大小通常对应节点的属性。每个矩形又按照相应节点的子节点递归的进行分割,知道叶子节点为止。

矩形树图的好处在于,相比起传统的树形结构图,矩形树图能更有效得利用空间,并且拥有展示占比的功能。矩形树图的缺点在于,当分类占比太小的时候文本会变得很难排布。相比起分叉树图,矩形树图的树形数据结构表达的不够直观、明确。

矩形树图的布局算法非常多,而且经常为可视化工程师津津乐道。但介绍具体实现并不是AntV目前的职责,有兴趣的同学可以参见拓展阅读部分。

英文名:Treemap, Rectangular Tree

矩形树图的构成

图表类型 矩形树图
适合的数据 带权的树形数据
功能 表示树形数据的树形关系,及各个分类的占比关系
数据与图形的映射 树形关系映射到位置,占比数值数据映射到大小。设置颜色增强分类的区分度
适合的数据条数 大于5个分类

矩形树图的应用场景

适合的场景

适合展示带权的树形数据

例子1:下图是2015年手机品牌及其下属手机型号的销量信息。

$.getJSON('./data/mobile.json',function (data) { var Stat = G2.Stat; var chart = new G2.Chart({ id: 'c1', width: 1000, height: 500, animate: false // 阻止动画 }); chart.source(data); chart.tooltip({ map: { title: 'name', value: 'value' } }); chart.axis(false); chart.legend(false); chart.polygon().position(Stat.treemap('1*value')) .color('name') .label('name') .style({ stroke: '#fff', lineWidth: 1 });; chart.render(); function findNode (name,nodes) { var rst = null; for (var i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.name === name) { rst = node; } if (!rst && node.children) { rst = findNode(name,node.children); } if (rst) { break; } } return rst; } var expanded = false; chart.on('plotclick',function(ev){ var point = ev.data; if (point) { var name = point._origin.name; var node = findNode(name,data); var nodes; if (!expanded) { // 未展开 if (node.children) { nodes = node.children; } else { nodes = [node]; } chart.clear(); chart.source(nodes); chart.polygon().position(Stat.treemap('1*value')).color(point.color) .label('name', { offset: -2, label:{ fontSize: 10 } }) .style({ stroke: '#fff', lineWidth: 1 }); chart.render(); expanded = true; } else { //已经展开 chart.clear(); chart.source(data); chart.polygon().position(Stat.treemap('1*value')).color('name') .label('name', { label: { fontSize: 12 } }) .style({ stroke: '#fff', lineWidth: 1 }); chart.render(); expanded = false; } } }); });

说明:

  • 同一级别的树通过算法,按各自权重大小(手机销量占比)将坐标系分割成若干个矩形块,设置颜色增强分类的区分度。
  • 交互,点击矩形块可下钻到子分支。

不适合的场景

没有权重关系,且需要明显展示层级关系,用分叉树图更合适

例子2:某公司组织部门图。第一个图是用矩形树图绘制,没有权重,层次不清。第二个图用分叉树图绘制,部门组织层级清晰明了。

var data = [{ "name": "总经理", "value":1 }, { "name": "运营总监", "value":1 }, { "name": "职能总监", "value":1 }, { "name": "人事部", "value":1 }, { "name": "行政部", "value":1 }, { "name": "财务部", "value":1 }, { "name": "服务总监", "value":1 }, { "name": "技术部", "value":1 }, { "name": "客服部", "value":1 }, { "name": "售后部", "value":1 }, { "name": "市场总监", "value":1 }, { "name": "企划部", "value":1 }, { "name": "推广部", "value":1 }, { "name": "广告部", "value":1 }, { "name": "公关部", "value":1 } ]; var Stat = G2.Stat; var chart = new G2.Chart({ id: 'c2', width: 1000, height: 500, animate: false // 阻止动画 }); chart.source(data); chart.tooltip({ map: { title: 'name', value: 'value' } }); chart.axis(false); chart.legend(false); chart.polygon().position(Stat.treemap('1*value')) .color('name') .label('name') .style({ stroke: '#fff', lineWidth: 1 });; chart.render();
var data = [{ "name": "总经理", "children": [{ "name": "运营总监", "children": [{ "name": "职能总监", "children": [{ "name": "人事部" },{ "name": "行政部" },{ "name": "财务部" }] },{ "name": "服务总监", "children": [{ "name": "技术部" },{ "name": "客服部" },{ "name": "售后部" }] },{ "name": "市场总监", "children": [{ "name": "企划部" },{ "name": "推广部" },{ "name": "广告部" },{ "name": "公关部" }] }] }] }]; var Layout = G2.Layout; var Stat = G2.Stat; var chart = new G2.Chart({ id: 'c3', width: 1000, height: 500, animate: false, plotCfg: { margin: [20,50] } }); // 不显示title chart.tooltip({ title: null }); // 不显示图例 chart.legend(false); // 使用layout,用户可以自己编写自己的layout // 仅约定输出的节点 存在 id,x,y字段即可 var layout = new Layout.Tree({ nodes: data, dx: 80 / 1000 // 单位宽度,由于按照宽高 1来计算的,所以需要传入比例值 }); var nodes = layout.getNodes(); var edges = layout.getEdges(); // 首先绘制 edges,点要在边的上面 // 创建单独的视图 var edgeView = chart.createView(); edgeView.source(edges); edgeView.coord().reflect(); // edgeView.axis(false); edgeView.tooltip(false); // Stat.link 方法会生成 ..x, ..y的字段类型,数值范围是 0-1 edgeView.edge() .position(Stat.link('source*target',nodes)) .shape('vhv') .color('#ccc'); // 自定义部门的图形 G2.Shape.registShape('point', 'depart', { drawShape: function(cfg, group) { var x = cfg.x; var y = cfg.y; var width = 60; var height = 30; var shape = group.addShape('rect', { attrs: { x: x - width / 2, y: y - height / 2, width: width, height: height, fill: '#fff', stroke: 'black' } }); return shape; } }); // 创建节点视图 var nodeView = chart.createView(); nodeView.coord().reflect(); //'polar' nodeView.axis(false); // 节点的x,y范围是 0,1 // 因为边的范围也是 0,1所以正好统一起来 nodeView.source(nodes, { x: {min: 0,max:1}, y: {min: 0, max:1}, value: {min: 0} }); nodeView.point().position('x*y').color('steelblue') .shape('depart') .label('name', { offset: 0 }) .tooltip('name'); chart.render();

矩形树图与其他图表的对比

矩形树图和马赛克图

  • 矩形树图用于展示树形数据,是关系型数据。马赛克图用于分析列表数据,是非关系型数据。

矩形树图和分叉树图(分叉树图介绍敬请期待)

  • 矩形树图用于展示带权的数据,分叉树图用于展示不带权的数据
  • 两个图表都用于展示层次数据,但是分叉树图展示的层次关系更清晰
  • 矩形树图能更多的展现树形结构内部的占比关系,分叉树图没有这个能力

矩形树图的扩展阅读

标签