數據可視化(7)--D3基礎

一直想寫寫D3,以爲D3真心比較強大,基本上你能想出來的圖表都能繪製出來,只不過使用起來比前幾個要稍麻煩一點。git

正好最近讀完了《數據可視化實戰》,將關於D3的知識梳理了一遍,寫這篇博客記錄一下。github

D3 是一個縮寫,它的全稱叫Data-Driven Documents(數據驅動的文檔)。D3是基於數據操做文檔的JavaScript庫。D3幫助你使用HTML,SVG和CSS生動的展示數據。D3不須要將你使用某個特定的框架,D3重點在於對主流瀏覽器的全兼容,同時結合了強大的虛擬化組件,以數據驅動的方式去操做DOM。數組

D3支持所謂的主流瀏覽器除了IE8及之前的版本。D3測試了火狐,Chrome、Safari、Opera和IE9。D3的大部分組件能夠在舊的瀏覽器運行,D3核心庫的最低運行要求:支持JavaScript和W3C DOM API.對於IE8,建議使用兼容性庫Aight庫.D3採用的是Selectors API的第一級標準,你要是考慮兼容性能夠預加載Sizzle庫。你得使用主流的瀏覽器以即可以支持SVG和CSS3的轉場特效。瀏覽器

官網地址:http://d3js.org/app

下載官方包 d3.v3.zip 或者添加以下代碼:框架

<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>

數據

var dataset = [1,2,3,4,5];
d3.select("body").selectAll("p")
    .data(dataset)
    .enter()
    .append("p")
    .text("New paragraph!");

結果以下圖dom

詳細的解釋svg

d3.select("body")
  選擇DOM 中的body 元素,把它交給連綴方法中的下一個方法。
.selectAll("p")
  選擇DOM 中的全部段落。由於尚未段落,因此返回空元素。能夠認爲這個空元素表明立刻就會建立的段落。
.data(dataset)
  解析並數出數據值。dataset 數組中有5 個值,於是此後的全部方法都將執行五遍,每次針對一個值。
.enter()
  要建立新的綁定數據的元素,必須使用enter()。這個方法會分析當前選擇的DOM 元素和傳給它的數據,若是數據值比對應的DOM 元素多,就建立一個新的佔位元素。而後把這個新佔位元素的引用交給鏈中的下一個方法。
.append("p")
  取得由enter() 建立的空佔位元素,並把一個p 元素追加到相應的DOM 中。而後它再把本身剛建立的元素交給鏈中的下一個方法。
.text("New paragraph!")
  取得新建立的p 元素,插入文本值。函數

將最後一行修改成測試

.text(function(d) { return d; });

結果以下

咱們用數據填充了每一個段落,機關都在data() 方法裏。在連綴方法中,只要調用data() 了,就能夠隨時建立一個接收d 爲輸入的匿名函數。與當前元素對應,方法data() 確保了每一個d 都會被賦予原始數據集中的一個值。隨着D3 遍歷每一個元素,「當前元素」的這個值也會跟着變化。好比,循環到第三次時,代碼會建立第三個p 元素,而d 就會被賦予數據集中的第三個值(即dataset[2])。因而,第三個段落的文本就是「15」。

SVG繪製

首先要建立一個SVG 元素,以便在其中保存全部圖形,先找到文檔的body 元素,而後在結束的</body> 標籤前添加一個新的svg 元素,並設置長寬,代碼以下

var svg = d3.select("body")
    .append("svg")
    .attr("width", 500)
    .attr("height", 50);

添加一些數據

var dataset = [ 5, 10, 15, 20, 25 ];

使用data() 迭代每一個數據點,爲它們分別建立一個圓形

var circles = svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle");

最後設置圖形的樣式

circles.attr("cx", function(d, i) {
        return (i * 50) + 25;
    })//設置x的位置
    .attr("cy", 50 / 2)//設置y的位置
    .attr("r", function(d) {
        return d;
    })//設置圓的半徑
    .attr("fill", "yellow")//設置填充顏色
    .attr("stroke", "orange")//設置圓的邊緣線顏色
    .attr("stroke-width", function(d) {
        return d / 2;
    });//設置圓的邊緣線的寬度

 

結果以下圖

比例尺

「比例尺是一組把輸入域映射爲輸出範圍的函數。」

先建立比例尺,設定值域爲100~500和實際範圍10~350,代碼以下

var scale = d3.scale.linear()
    .domain([100, 500])
    .range([10, 350]);

能夠測試一下scale

scale(100); // 返回10
scale(300); // 返回180
scale(500); // 返回350

添加數據集

var dataset = [
          [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
          [410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
        ];

能夠根據d3的max()和min()方法建立一個動態映射軸值的比例尺函數,max() 函數只是簡單地循環數組中的每一個值,而後找出其中最大的那個。min()則是找出其中最小的那個。

定義比例尺函數,其中w是svg寬,h是svg高。

var w = 500;
var h = 100;

var xScale = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) { return d[0]; })])
    .range([0, w]);
var yScale = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) { return d[1]; })])
    .range([0, h]);

 

使用比例尺函數處理數據,併到svg中顯示

svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
        return d[0];
    })
    .attr("cy", function(d) {
        return d[1];
    })
    .attr("r", function(d) {
        return Math.sqrt(h - d[1]);
    });

 

效果以下

 

d3.scale.linear() 還有幾個很是方便的方法。
nice()
告訴比例尺取得爲range() 設置的任何值域,把兩端的值擴展到最接近的整數。根據D3 的維基:「好比,值域[0.20147987687960267, 0.996679553296417]的優化值域爲[0.2, 1]。」這個方法對正常人都有用,由於人不是計算機,看到0.20147987687960267 這樣的數你必定會頭大。
rangeRound()
用rangeRound() 代替range() 後,則比例尺輸出的全部值都會舍入到最接近的整數值。對輸出值取整有利於圖形對應精確的像素值,避免邊緣出現模糊不清的鋸齒。
clamp()
默認狀況下,線性比例尺能夠返回指定範圍以外的值。例如,假如給定的值位於輸入值域以外,那麼比例尺也會返回一個位於輸出範圍以外的值。不過,在比例尺上調用clamp(true) 後,就能夠強制全部輸出值都位於指定的範圍內。這意味着超出範圍的值,會被取整到範圍的最低值或最高值(總之是最接近的那個值)。

 

除了線性(linear)比例尺,D3 還內置了另外幾個比例尺方法。
sqrt
平方根比例尺。
pow
冪比例尺,適合值以指數級變化的數據集。
log
對數比例尺。

quantize
輸出範圍爲獨立的值的線性比例尺,適合想把數據分類的情形。
quantile
與quantize 相似,但輸入值域是獨立的值,適合已經對數據分類的情形。
ordinal
使用非定量值(如類名)做爲輸出的序數比例尺,很是適合比較蘋果和桔子。
d3.scale.category10()、d3.scale.category20()、d3.scale.category20b() 和d3.scale.category20c()
可以輸出10 到20 種類別顏色的預設序數比例尺,很是方便。
d3.time.scale()
針對日期和時間值的一個比例尺方法,能夠對日期刻度做特殊處理。

 

數軸

接着上面的例子進行,建立數軸

var xAxis = d3.svg.axis()//建立通用的數軸函數
    .scale(xScale)//基於xScale比例尺工做
    .orient("bottom");//設置標籤相對數軸顯示在什麼地方。默認位置是底部。

 

在SVG 中生成數軸,放在腳本底部,以便在SVG 中的其餘元素都生成以後再生成數軸,這樣數軸就能夠出如今「上面」了。

svg.append("g")
  .attr("class", "axis") // 指定"axis" 類
  .call(xAxis);

 

效果以下

略難看,並且x軸的位置也不對。

修整一下數軸,在<head> 中的<style> 標籤裏寫兩條CSS 樣式規則。

.axis path, .axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
}
.axis text {
    font-family: sans-serif;
    font-size: 11px;
}

 

 用到SVG 變換(transform)了。添加一行代碼,把整個數軸分組平移到圖表下方,詳細以下

svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0," + (h - 20) + ")")
    .call(xAxis);

 

 效果以下

而後添加Y軸,作一些調整,最後JS文件以下

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
var dataset = [
    [ 5, 20 ],
    [ 480, 90 ],
    [ 250, 50 ],
    [ 100, 33 ],
    [ 330, 95 ],
    [ 410, 12 ],
    [ 475, 44 ],
    [ 25, 67 ],
    [ 85, 21 ],
    [ 220, 88 ]
];
var x = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) { return d[0]; })])
    .range([0, width]);

var y = d3.scale.linear()
    .domain([0, d3.max(dataset, function(d) { return d[1]; })])
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


svg.selectAll("circle")
    .data(dataset)
    .enter()
    .append("circle")
    .attr("cx", function(d) {
        return x(d[0]);
    })
    .attr("cy", function(d) {
        return y(d[1]);
    })
    .attr("r", function(d) {
        return 10;
    });
svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .append("text")
      .attr("class", "label")
      .attr("x", width)
      .attr("y", -6)
      .style("text-anchor", "end")
      .text("X軸");

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("class", "label")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Y軸");

最終效果以下

D3的基礎今天就到這裏~~

有時間的話,推薦讀一下《數據可視化實戰》~~

相關文章
相關標籤/搜索