基于D3.js实现分类多标签的Tree型结构可视化

全文共5270个字,4张图,预计阅读时间25分钟。

关键词: 可视化,D3.js,python,前端,代码

why

今天新来的实习生需要对部分分类文本进行多标签的检测,即根据已构建好的一、二级标签Excel文档,对众包平台人工标注的数据以及机器标注的数据进行评测。

此情此景,让我想起了曾经在实验做的文本多标签分类的工作,所以就想用Echart 或D3.js实现层级标签可视化为一个Tree的结构,方便实习生们查阅,提高工作效率。

说干就干!

How

处理数据

首先,找一个标准的基于D3.js实例程序,明确一下我们的工作目标以及步骤[数据的格式+前端代码]。

看一下需要将我们目前的结构化数据:

体育,篮球,NBA
体育,篮球,CNA
体育,篮球,CUBA
体育,足球,中超
体育,足球,欧冠
体育,羽毛球
体育,羽毛球,汤姆斯杯
数码,手机,iPhone
数码,手机,小米
数码,电脑,MacPro
数码,电脑,Dell
数码,电脑,小米
数码,照相机,索尼
数码,照相机,尼康
教育,大学,高数
教育,大学,英语
教育,高中,物理
教育,高中,化学
教育,高中,生物
教育,小学
教育,幼儿

标准的可以被D3.js加载的数据格式:

加载之后的Tree型结构效果图:

以上的Tree型图就是我们想要达到的目标。

我们需要将我们的数据,转换为D3.js可以加载的标准数据。

我决定使用python编写处理的脚本:编写的逻辑完全是自己瞎想的,如果各位有什么更好、更标准的方法,欢迎指出。

# coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )

dic={}

with open("testtag.txt") as f:
for i in f:
# print i
i=i.split(",")
k=str(i[0]).strip()
if k not in dic:
    dic[k]=[".".join(i[1:]).strip()]
    # 是为了预防存在二级标签的缺失
    dic[k].append(str(i[1]).strip())
    # 又不能存在重复,使用set去重
    dic[k]=list(set(dic[k]))
else:
    dic[k].append(str(i[1]).strip())
    dic[k].append(".".join(i[1:]).strip())
    dic[k]=list(set(dic[k]))

with open("3tag.csv","w") as w:
w.writelines("id,value"+'\n')
w.writelines("3Tag"+'\n')
for i in dic.keys():
w.writelines("3Tag."+i+'\n')
for j in dic[i]:
      w.writelines("3Tag."+str(i)+"."+str(j).strip()+'\n')

处理之后的结果存储到本地的文件3tag.csv中:

一定要完全按照标准的D3.js的格式处理的。

id,value
3Tag
3Tag.体育
3Tag.体育.篮球.CNA
3Tag.体育.足球.中超
3Tag.体育.篮球.CUBA
3Tag.体育.篮球
3Tag.体育.羽毛球
3Tag.体育.足球
3Tag.体育.羽毛球.汤姆斯杯
3Tag.体育.篮球.NBA
3Tag.体育.足球.欧冠
3Tag.教育
3Tag.教育.大学.高数
3Tag.教育.高中
3Tag.教育.幼儿
3Tag.教育.高中.生物
3Tag.教育.大学
3Tag.教育.大学.英语
3Tag.教育.高中.物理
3Tag.教育.小学
3Tag.教育.高中.化学
3Tag.数码
3Tag.数码.电脑.MacPro
3Tag.数码.手机.小米
3Tag.数码.照相机.索尼
3Tag.数码.电脑.Dell
3Tag.数码.手机.iPhone
3Tag.数码.电脑.小米
3Tag.数码.手机
3Tag.数码.电脑
3Tag.数码.照相机.尼康
3Tag.数码.照相机

注意事项:

正确的数据: ''' id,value 3Tag 3Tag.体育 3Tag.体育.篮球 3Tag.体育.篮球.CNA 3Tag.体育.足球.中超 3Tag.体育.足球 ''' 1.处理数据的过程中要注意,不允许存在隔级的情况: eg: ''' id,value 3Tag 3Tag.体育 3Tag.体育.篮球.CNA ''' *是错误,必须存在“3Tag.体育.篮球”这一级才可以,否则数据加载失败!

2.不允许存在重复的行数据,否则加载失败! ''' id,value 3Tag 3Tag.体育 3Tag.体育 3Tag.体育.篮球.CNA '''

所以,整个处理的过程中,其实最麻烦的就是数据的处理了。

前端的web界面

标准数据有了,剩下的就是需要一个前端的web界面,这个代码在上面的示例页面中已经有了,只需要我们自己替换为我们的数据源就可以了,我还是贴出自己的代码吧。

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node circle {
fill: #999;
}

.node text {
font: 10px sans-serif;
}

.node--internal circle {
fill: #555;
}

.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff,  -1px 0 0 #fff;
}

.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}

form {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
left: 10px;
top: 10px;
}

label {
display: block;
}

</style>
<form>
<label><input type="radio" name="mode" value="cluster" checked> Dendrogram</label>
<label><input type="radio" name="mode" value="tree"> Tree</label>
</form>

<!-- <iframe  src="http://10.73.20.41/mblog_info_test/library3_quality_mbblog_line_tag_distrib/" width="1300" height="1900"   frameborder="0"  name=""     scrolling="yes">   
</iframe> -->
<svg width="560" height="800"></svg>
<!-- <script src="d3.js"></script> -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(40,0)");

var tree = d3.tree()
.size([height - 400, width - 160]);

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

var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });

d3.csv("3tag.csv", function(error, data) {
if (error) throw error;

var root = stratify(data)
.sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); });

cluster(root);

var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);

var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });

node.append("circle")
.attr("r", 5);

node.append("text")
.attr("dy", 3)
.attr("x", function(d) { return d.children ? -8 : 8; })
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return  d.id.substring(d.id.lastIndexOf(".") + 1); });

d3.selectAll("input")
.on("change", changed);

var timeout = setTimeout(function() {
d3.select("input[value=\"tree\"]")
.property("checked", true)
.dispatch("change");
}, 1000);

function changed() {
timeout = clearTimeout(timeout);
(this.value === "tree" ? tree : cluster)(root);
var t = d3.transition().duration(750);
node.transition(t).attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
link.transition(t).attr("d", diagonal);
}
});

function diagonal(d) {
return "M" + d.y + "," + d.x
+ "C" + (d.parent.y + 100) + "," + d.x
+ " " + (d.parent.y + 100) + "," + d.parent.x
+ " " + d.parent.y + "," + d.parent.x;
 }
</script>
</body>

RESULT

最后,展示一下我们的成果:

以上就是本次层级标签可视化的实践,以后大家工作中再遇到多标签的问题,可以使用该方法快速的实现Tree型结构的可视化了,方便阅读与理解。

原文链接:https://www.jianshu.com/p/77708cfe3716

本文分享自微信公众号 - 人工智能LeadAI(atleadai)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏申龙斌的程序人生

零基础学编程017:画出我的公众号LOGO

在《零基础学编程014:小海龟做画》和《零基础学编程015:画些有趣的图案》里,我们已经可以用编程中的循环结构,加上turtle中的前进、转向等指令画些有趣的图...

32760
来自专栏互联网杂技

因为无聊和抠门,77岁老人用Excel作画

趁春光大好,去做你想做, 却未做过的事。 Excel作画 提起 Excel, 我们桌面基本都有这样一个图标, 通常它会被用来制表和做数据分析。 ? 不过到了一位...

389100
来自专栏互联网杂技

8pt栅格系统 - 1. 设计入门

介绍 此文意在帮助设计师快速而统一地完成界面布局。尤其对尺寸固定的移动界面有帮助,但对响应式web设计也有帮助。 与一般的设计指南相比,此文更适合一边设计一边...

39170
来自专栏菜鸟致敬

[菜鸟致敬⑨] 排版建议

最近有关注诸多大佬的博客亦或微信公众号,也时常阅读一些好的文章,它们的排版风格亦是各不相同。大概是大佬都专注于叠代码的缘故,对于文章的排版好坏可能抱着得过且过的...

12920
来自专栏无原型不设计

文字如何实现完美UI?文本排版设计告诉你

一部手机,电量充足,网络通畅,就足以让我们打发一天的时光,尽情沉浸在手机时代的缤纷世界里。这个信息资源无穷尽的手机网络世界,是设计师和开发者们在不停的探索中一...

38770
来自专栏极客编程

Material Design Lite ,简洁惊艳的前端工具箱

本文主要介绍Material Design设计语言的HTML/CSS/JS部分实现。

21230
来自专栏大数据钻研

在设计了100个弹框之后,这些是我的心得

最近2年一直在做WebApp相关项目,设计过上百个弹框,其中总结了一些心得,将透过以下文章介绍弹框在Web上的各种应用﹑技巧及表现。 什么是弹框? 弹框是一种交...

48790
来自专栏黑泽君的专栏

去除高清视频锯齿几个方法

  在使用DV拍摄制作视频时,经常被网友问到一个问题——为什么我拍出的视频在电脑上播放时会出现锯齿现象?有人认识是电脑配置太低,有人认为是摄像机出了故障,有人认...

3K30
来自专栏生信技能树

谁来拯救你 我的屁屁踢

审美的重要性 美究竟有没有一个标准这里不敢讨论。但是在长期的实践当中,人们大体总结出了一些形式美的规律,比如平衡、对称、对比、统一、变化以及黄金分割等。 做好P...

384100
来自专栏企鹅号快讯

程序猿必备的10款web前端动画插件三

1.一些想法预览或只是在悬停的文件夹上播放 这个想法是在悬停文件夹图标时显示一些动画,并显示某种内容的预览。我们想与你分享一些有趣的小悬停效果。这个想法是显示文...

28180

扫码关注云+社区

领取腾讯云代金券