【问题标题】:D3 Group label for xAxis ticksxAxis 刻度的 D3 组标签
【发布时间】:2019-08-19 14:13:55
【问题描述】:

我有一个类似的数据集:

[
  {
    date: '2019-01-01',
    value: 100,
    group: 1
  },
  {
    date: '2019-01-02',
    value: 200,
    group: 1
  },
  {
    date: '2019-01-03',
    value: 200,
    group: 2
  },
  {
    date: '2019-01-04',
    value: 200,
    group: 3
  },
  {
    date: '2019-01-05',
    value: 100,
    group: 3
  },
  {
    date: '2019-01-06',
    value: 250,
    group: 3
  }
]

我用 yAxis - value 和 xAxis - date 创建了一个线性图表。

如何通过group 字段值为 xAxis 实现附加标签,就像我在图片上显示的那样?

【问题讨论】:

    标签: d3.js axis-labels


    【解决方案1】:

    这个问题可能对你有帮助:grouped category bar chart with different groups in d3?

    但如果您只需要显示标签而不是按组显示颜色,那么您真正需要做的就是计算每个组中的值的数量:

    // first, group the data
    var groupedData = d3.nest()
            .key(function(d) { return d.group; })
            .rollup(function(v) { return v.length; })
            .entries(data)
    
    // then, get cumulative length of each group
    var groupedData = groupedData.map((d, i) => {
            const prev = nestedData[(i - 1)]
            const cumsum = prev ? d.value + prev.cumsum : d.value
            d.cumsum = cumsum
            return d
          })
    

    这段代码将数据转换成这样的:

        [
             {
                "key": 1,
                "values": 2,
                "cumsum": 2
             },
             {
                "key": 2,
                "values": 1,
                "cumsum": 3
             },
             {
                "key": 3,
                "values": 3,
                "cumsum": 6
             }
          ]
    

    现在您需要做的就是在图表标签下方添加组

    const svg = //your svg selector here
    
    const g = svg.append("g")
        .attr("class", "group-labels")
        .attr("x", 0)
        .attr("y", height + 30) //adjust this so that the group labels are below your labels
    
    g.selectAll(".group-label")
        .data(groupedData)
        .enter()
        .append("text")
        .attr("class", "group-label")
        .attr("x", function(d, i) { return xScale.bandwidth() * d.cumsum - xScale.bandwidth() * d.value / 2 })
        .attr("y", 0)
        .attr("text-anchor", "middle")
        .attr("dominant-baseline", "hanging")
    

    【讨论】:

    • 嗨,凯茜!非常感谢,您的回答很有帮助。就我而言,我在 xAxis 上有 scaleTime()。你能澄清我应该用什么来代替xScale.bandwidth()吗?
    • 即使是 2 年后,这也非常有帮助。感谢 Cathy 的回复和 ivan 提出这个问题。
    【解决方案2】:

    如果您使用scaleTime 创建这个,您需要在日期中添加时间,例如scaleLinearscaleBandscaleTime 需要准确的值来固定正确的坐标,但有些人忘记了日期也需要时间.

    <!DOCTYPE html>
    <html>
    <head>
    <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
      
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    </head>
    <body>
    
      <svg id="test" width="500" height="400"></svg>
    </body>
    </html>
    <script>
      var data = [
      {
        date: '2019-01-01',
        value: 100,
        group: 1
      },
      {
        date: '2019-01-02',
        value: 200,
        group: 1
      },
      {
        date: '2019-01-03',
        value: 200,
        group: 2
      },
      {
        date: '2019-01-04',
        value: 200,
        group: 3
      },
      {
        date: '2019-01-05',
        value: 100,
        group: 3
      },
      {
        date: '2019-01-06',
        value: 250,
        group: 3
      }
    ]
    
      // first, group the data
    var groupedData = d3.nest()
            .key(function(d) { return d.group; })
            .rollup(function(v) { return {
        count: v.length,
        lastDate: v[v.length-1].date + ' 12:00:00'
      }; })
        .entries(data)
    
    //console.log(groupedData)
    // then, get cumulative length of each group
    var groupedData = groupedData.map((d, i) => {
            const prev = groupedData[(i - 1)]
            const cumsum = prev ? d.value.count + prev.cumsum : d.value.count
            d.cumsum = cumsum
            return d
          })
    
    
    
    const svg = d3.select('svg')
    var width = 500
    var xscaleTime = d3.scaleTime()
        .domain([new Date('2019-01-01'), new Date('2019-01-06')])
        .range([0,500]).nice()
    
    
    
    var bandwidth = (xscaleTime(new Date(groupedData[1].value.lastDate))
                     - xscaleTime(new Date(groupedData[0].value.lastDate)))
    var padding = 20
    const b = svg.append("g")
    const t = b.append("g").call( d3.axisBottom().scale(xscaleTime))
    const g = b.append("g")
        .attr("class", "group-labels")
        .attr("y", 30) //adjust this so that the group labels are below your labels
    
    g.selectAll(".group-label")
        .data(groupedData)
        .enter()
        .append("text")
        .attr("class", "group-label")
        .attr("x", function(d, i) { 
          return xscaleTime(new Date (d.value.lastDate)) - bandwidth *((d.value.count-1)/2)
        })
        .attr("y", 50)
        .attr("text-anchor", "middle")
        .text(function(d,i){ 
          return 'is Group ' + d.key
        })
      
    </script>

    根据@Cathy 的回答,(请阅读她为您指出的好例子的答案)我为您编辑了一些,您可以通过编辑数据来制作她提供的示例(获取该组的最后日期和第一个日期)和this一起玩

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-21
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多