D3.js上手——餅狀圖

衛辰9發表於2019-04-09

餅狀圖是資料統計中經常用到的另一類圖表,餅圖可以直觀地顯示一個資料系列中各項的大小與各項總和的比例,本文將使用D3上手製作一個簡單的餅狀圖

什麼是佈局

佈局是D3中非常重要的內容,有了佈局D3才能畫出複雜的向量圖。但佈局並不是直接繪製圖形,只是將初始資料轉換成容易畫圖的圖形語言,畫圖工具能讀懂圖形語言來進行繪製。

在繪製餅狀圖中,例如有一組資料[1, 2, 3],只依靠這些資料是畫不出的,需要將這些資料轉化為圓形的起始角度和終止角度,第一塊的角度區域為[0, π/3],第二塊的角度區域為[π/3, π]……繪製工具能根據這些角度值進行繪製。佈局只進行資料轉換

D3還提供其他常用圖表的佈局函式,比如力導向圖(Force)、弦圖(Chord)、樹狀圖(Tree)、直方圖(Histogram)、分割槽圖(Partition)等,每種佈局有對應的API

確定資料

表格資料是來自w3schools的2016年9月的瀏覽器使用率

瀏覽器 佔比
Chrome 72.5%
IE 5.3%
Firefox 16.3%
Safari 3.5%
Opera 1.0%
Others 1.4%

對此設定以下二維陣列裝載這些資料

var dataset = [['Chrome', 72.5], ['IE', 5.3], ['Firefox', 16.3], ['Safari', 3.5], ['Opera', 1.0], ['Others', 1.4]];
複製程式碼

建立佈局

  • d3.pie() 構造一個新的餅佈局

構建一個餅佈局並接收資料

var pie = d3.pie()
            .sort(null) // 在建立佈局的時候,預設排序資料從大到小,設為null可以按照陣列預設順序排序
            .value(function(d){
              return d[1]
            });
複製程式碼

把資料轉換為餅圖繪製所需要的資料

var piedata = pie(dataset);
console.log(piedata);
複製程式碼

在控制檯輸出piedata,看看轉換後的資料

D3.js上手——餅狀圖

可以看到,原來的資料已經被轉換成6組適合畫圖的資料

  • data —— 保留原有資料
  • index —— 序號
  • startAngle —— 一段弧的起始角度
  • endAngle —— 一段弧的終止角度

生成弧生成器

雖然有了角度,但目前還是很難畫出我們想要的餅圖,還要用到D3中的路徑生成器。在svg中,path標籤的路徑數值往往十分複雜,手動去生成是不現實的,尤其是要生成各種複雜曲線的時候,好在D3提供了基本的路徑生成器,有線段、區域、弧生成器等。畫餅圖的時候需要用到弧生成器,幫助我們把轉換後的資料真正繪製出來

  • d3.arc() 建立一個新的弧生成器
  • arc.innerRadius([radius]) 設定內部半徑
  • arc.outerRadius([radius]) 設定外部半徑

這裡把畫布的四分之一作為外部半徑,內部半徑設為0就是餅圖,沒錯,設定大於0就是圓環圖

var outerRadius = width / 4;
var innerRadius = 0;
var arc = d3.arc()
            .outerRadius(outerRadius)
            .innerRadius(innerRadius);
複製程式碼

繪製餅圖

跟之前一樣,建立g組合標籤後,把piedata資料繫結至g標籤,這裡要用到D3的內建顏色,d3.schemeCategory10選了10種顏色,方便我們隨時使用,為餅圖的不同區域填色,不必為想不出好的顏色搭配而煩惱,當然也可以自定義顏色

D3.js上手——餅狀圖
var arcs = svg.selectAll('g')
              .data(piedata)
              .enter()
              .append('g')
              .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
// 呼叫內建顏色序列
var colors = d3.schemeCategory10;
arcs.append('path')
    .attr('fill', function(d, i){
      return colors[i];
    })
    .attr('d', function(d){
      return arc(d);
    });
複製程式碼

在path標籤中,給d屬性賦予資料經過弧生成器處理的值,這樣一個沒有標註的餅圖就完成了

D3.js上手——餅狀圖

新增標註

  • arc.centroid(arguments…) 獲取弧中心座標

接下來給餅圖加一些標註,以便更好地閱讀圖形,主要用到弧中心的概念,如下圖,黑點就是每個弧的中心,利用**arc.centroid()**可以獲取弧中心的座標,並且這個座標是相對圓形的相對座標。有了這個座標,可以很方便地在每個弧上新增文字標註

D3.js上手——餅狀圖

arc.centroid(d)是一個包含橫座標和縱座標的陣列[x, y],給座標乘以2倍以上的數值就把文字移到圓形外邊

arcs.append('text')
    .attr('transform', function(d, i){
      var x = arc.centroid(d)[0] * 2.8;
      var y = arc.centroid(d)[1] * 2.8;
      return 'translate(' + x + ', ' + y + ')';
    })
    .attr('text-anchor', 'middle')
    .text(function(d){
      var percent = Number(d.value) / d3.sum(dataset, function(d){
        return d[1];
      }) * 100;
      return d.data[0] + ' ' + percent.toFixed(1) + '%';
    })
複製程式碼

最後再加一些連線

arcs.append('line')
    .attr('stroke', 'black')
    .attr('x1', function(d){ return arc.centroid(d)[0] * 2; })
    .attr('y1', function(d){ return arc.centroid(d)[1] * 2; })
    .attr('x2', function(d, i){
      return arc.centroid(d)[0] * 2.5;
    })
    .attr('y2', function(d, i){
      return arc.centroid(d)[1] * 2.5;
    });
複製程式碼

由於最後幾個資料太小,標註文字會重疊到一起,這裡做了一個判斷處理來錯開資料值較小的文字,最後的效果圖如下所示

D3.js上手——餅狀圖

檢視完整示例程式碼

相關文章