d3js 分组条形图,这可能吗?

时间:2021-03-04 02:32:09

标签: d3.js

我想创建一个分组条形图,其中每个条形都是唯一的,而不是一个系列的一部分。

例如,想象一个条形图,显示每个主要城市的人口,按州分组。

使用 d3js 以及有关如何开始的任何指示是否可行?

谢谢 enter image description here

1 个答案:

答案 0 :(得分:1)

是的,这是可能的!

与大多数可视化一样,该过程是确定图表结构,然后确定如何将数据放入该结构的过程之一。在这种情况下,我认为最简单形式的数据看起来像这样......

  let groups = [
    { name:'one', values:[1,3,6,2] },
    { name:'two', values:[3,5,7,3,2,5] },
    { name:'three', values:[9,2,5] },
    { name:'four', values:[6] }
  ];

一组组,其中每个组都有一些属性,包括要表示为单个条形的一组值。

棘手的一点是计算出每个组和每个条沿水平轴的位置。我的想法是这样的:如果我们说每个条形的宽度为 1 个单位,那么我们希望在组之间有多少空间?也许一个半格,所以 1.5 个单位。现在,每个组将占用的空间等于其中的柱数(values 数组的长度),图表所需的总宽度将是这些值加上它们之间的空间的总和。

let dataWidth = d3.sum(groups, d=>d.values.length) + (groups.length-1) * groupPadding; 

我们还想遍历组并计算出它们的“起始位置”,即按照条形单位将组水平放置的位置,如下所示:

  let groupPadding = 1.5;
  let currentWidth = 0;
  groups = groups.map(group=>{
    group.width = group.values.length;
    group.startPosition = currentWidth;
    currentWidth += group.width+groupPadding;
    return group;
  });

接下来我们需要使用 d3-scale 制作 x 和 y 尺度。

对于 y 尺度,让我们保持简单并硬编码最大值

  const yScale = d3.scaleLinear()
    .domain([0,10])
    .range([chartHeight, 0]); // chart height is just your charts height in pixels

对于 x 比例,我们使用上面计算的 dataWidth 作为域的最大值,我们将使用此比例将条形单位转换为屏幕像素

 const xScale = d3.scaleLinear()
    .domain([0, barWidth)
    .range([0, chartWidth]); //chartWidth, the width of your chart in pixels

好的。现在我们有了绘制图表所需的一切知识。我所看到的图表结构所设想的......

groups 中的每个 group 都是一个 svg g 元素,根据其 startPosition 定位。这些 g 元素中的每一个都包含一组 rect 元素,每个值一个。在 g 元素中,您可能还想放置诸如组标签之类的内容。

大致上看起来像这样...

创建群组

const barGroups = chart.selectAll('g.bar-group')
    .data(groups)
    .enter()
    .append('g')
    .classed('bar-group', true)
    .attr('transform', group=>`translate(${xScale(group.startPosition)}, 0)`);

添加矩形

barGroups.each(function(group){
    const barGroup = d3.select(this);
    barGroup.selectAll('rect')
      .data(group.values)
      .enter()
      .append('rect')
        .attr('width', xScale(1))
        .attr('height', value => yScale(value))
        .attr('x', (value, i) => xScale(i))
        .attr('y', value => chartHeight - yScale(value));

这是一个将所有内容放在一起并填补空白以提供工作示例的块:Grouped Bars