D3.js用動畫渲染資料集的顯示
介紹
資料統計和資料分析離不開資料集。之前幾篇部落格(用D3.js進行醫療資料視覺化 (一)折線圖 (Line Chart) 等)基於的是國家衛生和計劃生育委員會統計資訊中心的資料,可以說是已經經過了加工,提煉總結出來的資料。而本文涉及的是原始資料集。如果按醫療資料來說,可以是電子病歷資料,個人健康資料等。但這兒重點介紹動畫效果的實現,不涉及任何與特定資料集有關的內容。
前一段時間有點閒暇時間,想玩一玩D3.js中的動畫效果。於是立馬想到一個經常碰到的場景:原始資料集的視覺化。目前有很多網站允許使用者上傳資料集,然後提供資料管理甚至分析的服務。在展現原始資料集的時候,大多用表格形式來呈現。一般來說,資料集的載入需要一點時間,所以這個過程如果能做的有趣一點,還是一件挺好玩的事兒。
可做的好玩兒的比如原本資料集(以2維為例)就是行X列規規矩矩排排站好,那進入的時候能不能模擬真實世界中站隊的規則:一隊隊先自己排好,然後集合到一塊固定的場地。再比如,集合完畢後,把特殊的位置標註出來,比如有缺失資料的地方。等等。
於是就做了一個簡單的程式模擬這一過程。效果如下圖。我用Chrome外掛Gif Cat抓的gif,初始狀態不知道為什麼沒抓下來。當個參考吧。
原理很簡單,需要原始碼的可以從這兒下載。
稍微展開說下目前的實現。
載入資料 Load Data
關鍵的原始碼見下面。
var circles = column.selectAll("circle") .data(data[j].data) .enter() .append("circle") .transition() .duration(1000) .each("start", function(d) { if(d.value == 1){ d3.select(this) .attr("fill", "white") .attr("r", 2) .attr("cx", width); }else if(d.value == 0){ d3.select(this) .attr("fill", "#222") .attr("cx", width); } }) .delay(function() { return j * (3000/datalen); }) .ease(easefuns[2]); circles .attr("cx", xScale(data[j].name)) .attr("cy", function(d, i) { return yScale(d.caze); }) .attr("class", function(d){ return"circle" + d.value; }) .each("end", function(d) { if(d.value == 1){ d3.select(this) .transition() .duration(500) .attr("fill", "white") .attr("r", 1); }else if(d.value == 0){ d3.select(this) .transition() .duration(500) .attr("fill", "#222") .attr("r", 1); } }); }
載入資料時的動畫有幾個關鍵點:
1. 每個點進入螢幕之前的狀態,由circles. each("start",function(d) {…})來決定。比如這兒有值的點就渲染成白色大圓點;而缺失值的點就是隱藏的(顏色與背景色相同)。
2. 點從螢幕邊緣飛到最終位置的節奏,由circles.delay()和circles.ease()共同決定。circles.delay()設定點進入螢幕的延遲時間。為了讓資料點一列一列依次進入,這兒的circles.delay()函式實現將j(列索引)作為了變數,越左邊的列進入的越早。有興趣的同學可以把circles.delay()的返回設成一個常數試試不一樣的進入效果。circles.ease()包含了好多可選的緩動函式,規定了資料點從一個位置到另一個位置是如何過渡的。目前使用的是cubic-in-out。模擬的是自然站隊場景中快速進入,精確佔位的理念。easefuns裡面包含了不同的函式,可以試試它們不同的效果。MikeBostock大神已然想到有人會對這些函式好奇,做了一個展示的頁面:https://bl.ocks.org/mbostock/248bac3b8e354a9103c4
3. 到達最終位置後的狀態,由circles. each("end",function(d) {…})來決定。這兒就把有效點渲染回白色小圓點了。
高亮缺失資料 Highlight Missing Data
原始碼見下面。
nodes
.transition()
.duration(1000)
.delay(500)
.attr("fill", "red")
.attr("r", 3)
.transition()
.duration(1000)
.attr("fill", "#222")
.attr("r", 1);
這兒主要就是通過nodes.transition()帶著動畫函式duration()和delay(),並結合各種樣式的設定。簡單來說,這兒的效果就是先將缺失點高亮成紅色大圓點,然後又再次隱藏。
渲染效率
最後再扯兩句渲染效率。D3.js對動畫的渲染有其侷限性,就是當節點增多時,效率會逐步降低。原始碼中包含若干個樣例資料集。比如data-20-10.csv表示20列,10行的資料集。當渲染data-20-10.csv、data-200-10.csv時,我的瀏覽器基本上還能勝任(MacbookPro, Chrome v51)。但對於data-200-100.csv以及更多資料的資料集,能明顯感覺到渲染的遲滯。
這個也許不是D3.js的錯,而是瀏覽器的問題。不知道大家有沒有這方面的資料,推薦一下。