全文共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