与D3.js分组的堆栈图表

nan*_*aks 6 javascript d3.js

我是D3的新手,我遇到了一些问题.想知道是否有人可以提供帮助.

我正在尝试使用d3创建分组堆栈图表.图的性质是每个组有2个条,第二个的值取决于第一个条.我希望第二个栏能够分解我在第一个栏上的内容.一个简单的例子就是如果说第一个柱上的值{x: 0, y: 3, y0: 0},那么第二个柱应该是{x: 0, y: 1, y0: 0}, {x: 0, y: 1, y0: 1}, {x: 0, y: 1, y0: 2}

因此,对于将为第一个条形图绘制的数据:

    {
        "series": "A",
        "values": [{
          "x": 0,
          "y": 1,
        },
        {
          "x": 1,
          "y": 2,
        },
        {
          "x": 2,
          "y": 3,
        },
        {
          "x": 3,
          "y": 1,
        },
        {
          "x": 4,
          "y": 3,
        }
   ]},
   {
        "series": "B",
        "values": [{
          "x": 0,
          "y": 3,
        },
        {
          "x": 1,
          "y": 1,
        },
        {
          "x": 2,
          "y": 1,
        },
        {
          "x": 3,
          "y": 5,
        },
        {
          "x": 4,
          "y": 1,
        }]
    }
Run Code Online (Sandbox Code Playgroud)

我会将第二个堆积条形图的值设为:

{
  "series": "A",
  "values":
    [ { x: 0, y: 1, y0: 0 },
      { x: 1, y: 1, y0: 0 },
      { x: 1, y: 1, y0: 1 },
      { x: 2, y: 1, y0: 0 },
      { x: 2, y: 1, y0: 1 },
      { x: 2, y: 1, y0: 2 },
      { x: 3, y: 1, y0: 0 },
      { x: 4, y: 1, y0: 0 },
      { x: 4, y: 1, y0: 1 },
      { x: 4, y: 1, y0: 2 }]
},
{
  "series": "B",
  "values":        
   [
      { x: 0, y: 1, y0: 1 },
      { x: 0, y: 1, y0: 2 },
      { x: 0, y: 1, y0: 3 },
      { x: 1, y: 1, y0: 1 },
      { x: 2, y: 1, y0: 1 },
      { x: 3  y: 1, y0: 1 },
      { x: 3, y: 1, y0: 2 },
      { x: 3, y: 1, y0: 3 },
      { x: 3, y: 1, y0: 4 },
      { x: 3, y: 1, y0: 5 },
      { x: 4, y: 1, y0: 1 },
    ]
}
Run Code Online (Sandbox Code Playgroud)

我使用了一些代码,我可以从我看到的示例中找到并尝试使其工作.这是我到目前为止所能做到的:

见插图

我将不胜感激任何帮助.谢谢

查看我想要实现的屏幕截图. 预计-图

tha*_*Guy 3

这是我使用您提供的数据整理的小提琴:https://jsfiddle.net/thatoneguy/nrjt15aq/8/

数据 :

var data = [
{ x: 0, y: 1, yheight: 0 },
{ x: 1, y: 1, yheight: 0 }, 
{ x: 1, y: 1, yheight: 1 }, 
{ x: 2, y: 1, yheight: 0 }, 
{ x: 2, y: 1, yheight: 1 },
{ x: 2, y: 1, yheight: 2 }, 
{ x: 3, y: 1, yheight: 0 }, 
{ x: 4, y: 1, yheight: 0 }, 
{ x: 4, y: 1, yheight: 1 }, 
{ x: 4, y: 1, yheight: 2 }
];
Run Code Online (Sandbox Code Playgroud)

需要对这些数据进行排序,以便可以将其正确地输入到堆叠条形图中。例如,从此链接:https://bl.ocks.org/mbostock/3886208您可以看到数据如下所示(我将其转换为 json):

{
  "State": "WA",
  "Under 5 Years": 433119,
  "5 to 13 Years": 750274,
  "14 to 17 Years": 357782,
  "18 to 24 Years": 610378,
  "25 to 44 Years": 1850983,
  "45 to 64 Years": 1762811,
  "65 Years and Over": 783877
}
Run Code Online (Sandbox Code Playgroud)

你的地方是分开的。所以,我编辑了你的(目前是手工编辑的,但可以编写一个函数来做到这一点)。所以你的数据现在看起来像这样:

   var data = [
    { x: 0, yHeight0: 1, yHeight1: 0, yHeight2: 0 }, 
    { x: 1, yHeight0: 1, yHeight1: 1, yHeight2: 0 },
    { x: 2, yHeight0: 1, yHeight1: 1, yHeight2: 2 }, 
    { x: 3, yHeight0: 1, yHeight1: 0, yHeight2: 0 },  
    { x: 4, yHeight0: 1, yHeight1: 1, yHeight2: 2 }
    ]
Run Code Online (Sandbox Code Playgroud)

注意不同的yHeights. 这些代表了数据中的不同高度,但我已将它们全部分组。根据具有相同的 x 值对它们进行分组。

现在我需要一些时间来解释一切,但我会解释基础知识。

请记住,我已经脱离了上面链接的示例。该示例具有以下颜色域:

var color = d3.scale.ordinal()
  .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
Run Code Online (Sandbox Code Playgroud)

他们知道他们将拥有多少个不同的堆栈。我暂时保留了这些,但可以更改。然后使用该比例赋予数据更多属性:

color.domain(d3.keys(data[4]).filter(function(key) {
  return key !== "x";
}));
Run Code Online (Sandbox Code Playgroud)

上面的函数是返回所有不同的堆栈(在您的情况下是 yHeights )。下面的函数使用这些属性,并为您提供有助于确定这些堆栈的高度和 y 位置的属性。

data.forEach(function(d) {
  var y0 = 0;
  d.ages = color.domain().map(function(name) {
    return {
      name: name,
      y0: y0,
      y1: y0 += +d[name]
    };
  });
  d.total = d.ages[d.ages.length - 1].y1;
});
Run Code Online (Sandbox Code Playgroud)

现在绘制它们:

var firstRects = state.selectAll("firstrect")
  .data(function(d) {
    return d.ages;
  })
  .enter().append("rect")
  .attr("width", x.rangeBand() / 2)
  .attr("y", function(d) { return y(d.y1); })
  .attr("height", function(d) { return y(d.y0) - y(d.y1); })
  .style("fill", function(d) { return color(d.name); }) 
  .style('stroke', 'black');
Run Code Online (Sandbox Code Playgroud)

这只为您提供了一个简单的堆积条形图,但您想要另一个带有数字的图表。因此,我通过将另一个条形图附加到同一轴来做到这一点,如下所示:

var secondRects = state.selectAll("secondrect")
  .data(function(d) { return d.ages; })
  .enter().append("rect")
  .attr("width", barWidth)
  .attr("y", function(d) {  return y(d.y1); })
  .attr("height", function(d) { 
    if (y(d.y0) - y(d.y1)) d.barHeight = y(d.y0) - y(d.y1); //this sets a height variable to be used later
    return y(d.y0) - y(d.y1);
  }) 
  .style("fill", 'white')
  .style('stroke', 'black')
  .attr("transform", function(d) {
    return "translate(" + (x.rangeBand() / 2) + ",0)";
  });
Run Code Online (Sandbox Code Playgroud)

现在来看一下这方面的数字:

var secondRectsText = state.selectAll("secondrecttext")
  .data(function(d) { 
    for (i = 0; i < d.ages.length; i++) {
      if (isNaN(d.ages[i].y0) || isNaN(d.ages[i].y1)) { 
        d.ages.splice(i--, 1);
      }
    }
    console.log('dages', d.ages);
    return d.ages;
  })
  .enter().append("text")
  .attr("width", barWidth)
  .attr("y", function(d) { 
    return y(d.y1);
  })
  .attr("transform", function(d) { 
  if(d.barHeight){ //if it hasnt got barheight it shouldnt be there
    return "translate(" + (barWidth + barWidth / 2) + "," + d.barHeight/2 + ")";
    } else {
     return "translate(" + 5000 + "," + 5000 + ")";
    }
  })
  .text(function(d, i) {
    return i;
  });
Run Code Online (Sandbox Code Playgroud)

检查数据设置以使其不使用任何空值。我可以继续解释我所做的事情,但希望您能够足够理解代码以将其实现到您的代码中。

从这里我将继续创建一个组织数据的函数,即将所有具有相同 x 值的值分组,这样您就不必手动编辑。

希望有帮助,再次为很长的答案道歉:P

这是所有代码,以防小提琴故障:

var data = [
{ x: 0, y: 1, yheight: 0 },
{ x: 1, y: 1, yheight: 0 }, 
{ x: 1, y: 1, yheight: 1 }, 
{ x: 2, y: 1, yheight: 0 }, 
{ x: 2, y: 1, yheight: 1 },
{ x: 2, y: 1, yheight: 2 }, 
{ x: 3, y: 1, yheight: 0 }, 
{ x: 4, y: 1, yheight: 0 }, 
{ x: 4, y: 1, yheight: 1 }, 
{ x: 4, y: 1, yheight: 2 }
];
Run Code Online (Sandbox Code Playgroud)
{
  "State": "WA",
  "Under 5 Years": 433119,
  "5 to 13 Years": 750274,
  "14 to 17 Years": 357782,
  "18 to 24 Years": 610378,
  "25 to 44 Years": 1850983,
  "45 to 64 Years": 1762811,
  "65 Years and Over": 783877
}
Run Code Online (Sandbox Code Playgroud)
   var data = [
    { x: 0, yHeight0: 1, yHeight1: 0, yHeight2: 0 }, 
    { x: 1, yHeight0: 1, yHeight1: 1, yHeight2: 0 },
    { x: 2, yHeight0: 1, yHeight1: 1, yHeight2: 2 }, 
    { x: 3, yHeight0: 1, yHeight1: 0, yHeight2: 0 },  
    { x: 4, yHeight0: 1, yHeight1: 1, yHeight2: 2 }
    ]
Run Code Online (Sandbox Code Playgroud)

编辑 :

这是小提琴,它可以从提供的图像中准确地为您提供所需的内容(有点hacky,但它有效:)): https: //jsfiddle.net/thatoneguy/nrjt15aq/10/

var color = d3.scale.ordinal()
  .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
Run Code Online (Sandbox Code Playgroud)
color.domain(d3.keys(data[4]).filter(function(key) {
  return key !== "x";
}));
Run Code Online (Sandbox Code Playgroud)
data.forEach(function(d) {
  var y0 = 0;
  d.ages = color.domain().map(function(name) {
    return {
      name: name,
      y0: y0,
      y1: y0 += +d[name]
    };
  });
  d.total = d.ages[d.ages.length - 1].y1;
});
Run Code Online (Sandbox Code Playgroud)