深入淺出d3.js數據可視化之道(5)(續)

在之前的折線制作過程中,我們選擇使用的平滑曲線,這一節我們學習一下帶錨點的折線圖配合區域圖的制作方法。

準備的數據

const  line0_data = [
  {
      type: "歷史平均",
      value: [
              ['2016/07', 1.4],
              ['2016/08', 1.5],
              ['2016/09', 1.8],
              ['2016/10', 1.9],
              ['2016/11', 1.6],
              ['2016/12', 2.5],
              ['2017/01', 2.1],
              ['2017/02', 2.6],
              ['2017/03', 2.4],
              ['2017/04', 2.7]
           ]
  },
  {
      type: "行業平均",
      value: [
            ['2016/07', 1],
            ['2016/08', 1.3],
            ['2016/09', 1.2],
            ['2016/10', 1.7],
            ['2016/11', 1.4],
            ['2016/12', 2.2],
            ['2017/01', 2.1],
            ['2017/02', 2.4],
            ['2017/03', 2.0],
            ['2017/04', 1.8]
           ]
  },
  {
    type: "當前商品",
    value: [
          ['2016/07', 1.2],
          ['2016/08', 1.4],
          ['2016/09', 1.8],
          ['2016/10', 1.9],
          ['2016/11', 1.8],
          ['2016/12', 2.4],
          ['2017/01', 2.1],
          ['2017/02', 2.1],
          ['2017/03', 2.0],
          ['2017/04', 1.4]
         ]
}

]

繪制折線圖及圖例

上一節這部分已經詳細介紹過,這里我們直接上代碼,有問題的同學可以參考深入淺出數據可視化之道(5)

js部分

 const data = line0_data;

    var initWidth = 340
    var initHeight = 500

    var padding = { left:40, top:20, right:20, bottom: 40}

    var height = initWidth - padding.top - padding.bottom
    var width  = initHeight - padding.left - padding.right


    var svg = d3.select("body")
                .append("svg")
                .attr("id", "chart")
                .attr("width", width)
                .attr("height", height)
                .style("padding-left", padding.left)
                .style("padding-right", padding.right)
                .style("padding-top", padding.top)
                .style("padding-bottom", padding.bottom)


     //添加y軸坐標軸

        //y軸比例尺
        let nums = [...data[0]["value"], ...data[1]["value"]].map(function(e){
            return e[1]
        })
        let yScale = d3.scaleLinear()
         .domain([0, d3.max(nums)*1.5])
         .range([height , 0]);

         let _yScale = d3.scaleLinear()
         .domain([0, d3.max(nums)*1.5])
         .range([0, height]);

        //定義y軸
        let yAxis = d3.axisLeft(yScale).ticks(6).tickSize(0.5);

        //添加y軸
        svg.append("g")
        .attr("class","axis")
        .attr("transform","translate(" + 0 + "," + 0 + ")")
        .call(yAxis);

     //添加x軸坐標軸

         //x軸比例尺
         let years = data[0]["value"].map(function(e){
                    return e[0]
          })

         const step = width / years.length
        
         let xScale = d3.scaleBand()
                        .domain(years)
                        .rangeRound([0, width])
 

        let _xScale =  d3.scaleBand()
                       .domain([0, width])
                       .rangeRound(years)

        //定義x軸
        let xAxis = d3.axisBottom(xScale).ticks(0)

        //添加x軸
         svg.append("g")
            .attr("class","axis-x")
            .attr("transform","translate(" + "0 ," + height + ")")
            .call(xAxis);


        //添加
       // gridlines in y axis function
       function make_y_gridlines() {
        return d3.axisLeft(yScale)
            .ticks(6)
    }


          // add the Y gridlines
        var grid =  svg.append("g")
            .attr("id", "grid")
            .call(make_y_gridlines()
                .tickSize(-width)
                .tickFormat("")
            )
        //--------------以下是繪制圖形-------------

        //創建一個直線生成器
        var linePath = d3.line()
                         .x( function(d){ return xScale(d[0]) + step/2 })
                         .y( function(d){ return yScale(d[1])})


        var colors = ["rgb(0, 188, 212)", "rgb(255, 64, 129)", '#955694']


        //添加路徑
        svg.append("g").selectAll("path")
            .data(data)
            .enter()
            .append("path")
            .attr("transform","translate(0, 0)")
            .attr("d", function(d){
                return linePath(d.value)
            })
            .attr("fill", "none")
            .attr("stroke-width", "2px")
            .attr("stroke", function(d, i){
              return colors[i]
            })

        // 添加節點
        var circles = svg.append("g")
                        .selectAll("g")
                        .data(data)
                        .enter()
                        .append("g")
                        .attr("class", function(d,i){return d.type})
        
          circles.selectAll("circle")
              .data(function(d){
                 return d.value
              })
              .enter()
              .append("circle")
              .attr("cx", function(d){
                 return xScale(d[0]) + step/2
                })
              .attr("cy", function(d){
                 return height - _yScale(d[1])
               })
              .attr("r", 4)
              .attr("fill", function(d, i){
                 var type = d3.select(d3.select(this)._groups[0][0].parentNode).attr("class")
                 var ii = data.findIndex((val, index) =>{
                            return val.type == type
                         }
                        )
                return colors[ii]
              })

        var cover =svg.append("g")

            cover.selectAll("rect")
                .data(data)
                .enter()
                .append("rect")
                .attr("width", 10)
                .attr("height", 10)
                .attr("fill", function(d, i){
                  return colors[i]
                })
                .attr("transform", function(d, i){
                    return `translate(10, ${(i)*20})`
                })


            cover.selectAll("text")
                  .data(data)
                  .enter()
                  .append("text")
                  .text(function(d, i){
                    return d.type
                  })
                  .attr("transform", function(d, i){
                      return `translate(27, ${(i)*20})`
                  })
                  .attr("font-size", '12px')
                  .attr("dy",function(){
                    return '0.75em'
                  })
                  .attr("fill", function(){
                    return '#333'
                  })

       // 偏移文字
       d3.selectAll('.axis-x .tick text')
         .attr("dy",'1em')
         .attr('dx', '-2em')

style部分

  body{
      font-family: "helvetica";
      background-color: #fff;
      margin:0;
      padding:100px
    }

    svg {
        box-sizing: content-box
    }

    .axis path {
        display: none;     
    }
    .axis .tick line{
        opacity: 0
    }
    .axis-x path {
        stroke: #aaa;
        stroke-width: 1
    }
    .axis-x .tick line{
        stroke: #aaa;
        stroke-width: 1
    }
    .axis-x .tick text{
        transform: rotate(-30deg);
    }
    
    #grid line {
      stroke: #aaa;
      stroke-width: 1
    }
    #grid .tick:nth-child(2) {
      display: none
    }
    #grid path {
      display: none
    }
    .line_y .domain{
        stroke: yellow;
        stroke-width: 2
    }

實現的效果

添加錨點的折線圖

生成區域

這里我們將學習一個新的生成器,區域生成器
首先我們先了解一下基本概念:
區域生成器主要是生成一塊區域,類似于直線生成器。
其數據訪問器有x().x0().x1().y().y0().y1()這幾項,數量比較多但是不需要同時都使用

一個簡單的區域圖

 const data = [80, 90, 120, 110, 180, 220]
 var areaPath = d3.area()
                     .x(function(d,i){return 20+i*70})
                     .y0(function(d, i){return height})
                     .y1(function(d,i){return height - d})

   var area= svg.append("path")
                    .attr("d", areaPath(data) )
                    .attr('fill', "rgba(0,0,255,0.4)")

生成的效果


區域圖

結合圖示:


參數示意圖

這里我們添加的是x軸方向的區域圖,因此x只需取一個值即可。如圖示,y0代表區域圖節點底部坐標,y1代表區域圖節點頂部坐標。區域圖通過一個個類似‘節點線’的東西構成了一個完整的面積圖。

給折線圖添加區域圖

 //生成河流的數據
       const max_min = [
            ['2016/07', 0.4, 2.0],
            ['2016/08', 1.0, 1.8],
            ['2016/09', 1.1, 2.2],
            ['2016/11', 1.2, 2.4],
            ['2016/12', 2.0, 2.7],
            ['2017/01', 1.5, 2.5],
            ['2017/02', 1.9, 3.1],
            ['2017/03', 1.5, 3.0],
            ['2017/04', 1.0, 3.2]
        ]
// 添加區域圖
        var areaPath = d3.area()
                          .x(function(d){ return xScale(d[0]) + step/2 })
                          .y0(function(d){  return yScale(d[2]) })
                          .y1(function(d){  return yScale(d[1]) })

        var river = svg.append("path")
                        .attr("d", areaPath(max_min) )
                        .attr('fill', "rgba(0,0,255,0.2)")

最終生成的效果


折線圖與區域圖結合顯示價格波動區間

源碼地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容