深入浅出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阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容