D3组标签用于x轴刻度线。

3

我有一个类似的数据集:

[
  {
    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
  }
]

我已经创建了一个具有 value 的 yAxis 和 date 的 xAxis 的线性图表。

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

enter image description here

3个回答

3
这个问题可能会对你有帮助:如何在 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")

嗨,Cathy!非常感谢,你的回答非常有帮助。在我的情况下,我在x轴上使用了scaleTime()。你能否澄清一下,我应该使用什么代替xScale.bandwidth() - ivan
1
即使两年后,这仍然非常有帮助。感谢Cathy的回复和Ivan提出这个问题。 - drewkiimon

1
如果您使用scaleTime创建此内容,则需要在日期中添加时间,就像scaleLinearscaleBand一样,scaleTime需要确切的值才能将正确的坐标固定,但有些人忘记了日期也需要时间。

<!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 进行操作,使其与她提供的示例类似。


0

1)添加“大属性”以显示月份名称作为分组

 svg.call(axis)  .selectAll("text")
          .attr("class", (dt) => {
            if (isFirstWeekOfDate(dt)) return "big";
            return "small";
          });

2) 找到.big,然后获取父节点并添加另一个“text”初始化

d3.selectAll(".big").each((d, i, ref) => {
  console.log(d, ref[i]);
  d3.select(ref[i].parentNode)
    .attr("class", "par")
    .append("text")
    .attr("dy", "0em")
    .attr("y", -17)
    .attr("fill", "currentColor")
    .text(d.format("MMM"));
  return d;
});

  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接