基於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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章