hello,data!
在進入d3.js之前,我們先用一個小例子回顧一下將數據可視化的基本流程。
- 任務
用橫向柱狀圖來直觀顯示以下數據:
- var data = [10,15,23,78,57,29,34,71];
簡單地思考一下,要完成這個任務有兩個問題需要解決:
- 用什么可視元素來表現橫向柱?
- 數據對應到可視元素的什么屬性?
這個不算困難,我們使用HTML的DIV元素來實現,代碼參見http://www.hubwiz.com/course/54fd40cfe564e50d50dcf284/:快速入門第一頁
試着改變一下示例代碼中變量data的內容,體會一下數據驅動 的含義。
數據可視化與d3.js
將數據以圖形的方式表現出來,這個過程就是數據可視化。
沒錯,一圖勝千言。我們很難從枯燥的數字中發現規律與異常,但很善於從圖形 中發現模式。隨着人類所擁有數據規模的日益擴大,數據可視化逐漸成為一個重要 的不可或缺的技術手段。
d3.js是一個優秀的數據可視化庫,可以讓我們方便快捷地實現數據到圖形的變換。 不過,在開始后續的教程之前,先打個預防針,希望你不要誤解d3.js :
- d3.js不是一個圖形繪制庫
很多人驚詫於這一點,但不得不提。d3依賴於標准的web技術來繪制可視化元素,比如 HTML、SVG、CSS。使用d3需要我們對這些標准技術有基礎的了解。
- d3.js是一個基於集合概念的DOM操作庫
d3不是圖形繪制庫,但它對DOM操作進行了封裝。和jQuery類似,d3依賴於選擇符選 中一組元素,建立一個集合,然后使用集合對象的方法操作DOM。
- d3.js的大量功能集中在數據處理方面
要將數據映射到圖形,有很多瑣碎的工作,比如數據范圍的變換、插值的計算、布局的 計算等等。d3.js的大量功能是集中在這樣的數據處理方面的。
- d3.js的核心是對數據和可視化元素的匹配
d3將數據可視化抽象為數據與可視化元素的匹配,一個數據對應一個可視化元素,一個 數值對應一個可視化元素的屬性。d3封裝了這個匹配的復雜過程,讓我們得以簡單的 通過聲明數據和可視化元素來完成數據可視化的任務。
d3的四把斧:hello,d3
在HTML文件中引入d3.js后,我們就獲得了一個全局變量:d3。d3.js 的功能就通過這個對象暴露出來。
我們使用d3的API重寫前面的示例,代碼已經預置到→_→。
這個例子展示了d3.js實現數據可視化的典型理念:基於集合運算的 聲明式數據可視化。
請你注意上圖中使用d3時經典的四把斧:d3總是要求使用者聲明兩個集合:DOM對象集和數據集, 並根據集合運算實施數據與DOM對象的匹配,最后通過修改匹配的DOM對象來獲得 可視化的效果。
d3第1斧:聲明DOM對象集
d3的數據可視化流程總是從選中一組DOM元素建立一個集合對象開始。 在示例中,我們通過:
- var selection1 = d3.select("#barChart").selectAll(".bar");
試圖在文檔DOM樹中選擇div#barChart中的所有div.bar。 我們將這一步返回的DOM集合保存到變量selection1中。
你應該會注意到,這是一個空集合!
這有點意思。
- d3允許聲明一個空集合
在jQuery中,如果我們的選擇符沒有選中任何HTML元素,那么后面的所有操作都沒有意義了。 但是,d3允許我們選不中任何元素來來建立一個空集合。
因為,d3還有第2斧,用數據來影響這個空集合。
size()方法返回集合中所有DOM元素的數量。在→_→的示例中,你可以看到,selection1 確實是一個空集合:它有0個DOM元素。
d3第2斧:聲明數據集
我們在第一步返回的selection1上執行data()方法聲明要展示的數據:
- var selection2 = selection1.data(data);
我們知道這個數據集不是空的,它有8個數據項。在這一步,d3將數據集和DOM 對象集進行比較,返回一個新的集合selection2。
我們看到,selection2的DOM元素數量也是0。
匹配計算
data()方法執行時對數據集和DOM元素集進行了匹配計算, 直接返回的結果就是兩個集合的共有部分。由於DOM元素集是空的,所以結 果一定也沒有任何DOM元素:
但是,匹配計算的結果有兩個重要的方法,讓我們可以獲得數據集合DOM元素集的 差異在哪里:
- enter() : 獲得數據集中比DOM元素集中多出來的數據
- exit() :獲得DOM元素集中比數據集中多出來的數據
示例(http://www.hubwiz.com/course/54fd40cfe564e50d50dcf284/:快速入門第五頁)顯示了通過data()操作,目前獲得的選擇集中成員數目還是0。
d3第3斧:獲得結果集
繼續使用集合的enter()方法,我們可以獲取缺失的DOM對象集合(以數據集為 對比基准):
- var selection3 = selection2.enter();
由於原始DOM集合為空,而數據集有8項,那么selection3中也將有8項描述8個缺失的 DOM對象:
d3第4斧:實施DOM操作
使用集合的append()方法,我們創建缺失的DOM對象:
- var selection4 = selection3.append("div");
這時selection4已經是有8個div元素的集合了,在這個集合上我們使用text() 方法設置每個元素的文本內容:
- selection4.text(function(d){return d;});
你注意到text()方法的參數是一個函數!讓我解釋一下。
selection4是一個集合,內有8個div元素,我們經過之前的三斧,這每個元素都已經有對應 的數據了(d3負責管理其對應關系),比如,第一個DIV元素對應的是10,第二個DIV元素對應 的是15......
每當集合的方法被調用時,它都檢查傳入的參數,如果傳入的參數是一個函數,d3就對集 合中的每個DOM元素執行一次這個函數,並傳入這個DOM元素對應的數據。
我們接着使用classed()方法設置每個元素的CSS類為"bar":
- selection4.classed("bar",true)
最后使用width()方法使用每個元素對應的數據,設置其寬度。這個可以理解了吧?