如何使用d3.js正确制作倒置的堆叠图?

时间:2016-07-05 06:19:02

标签: javascript d3.js

“Web的交互式数据可视化”第11章介绍了如何使用D3.js库创建堆积条形图。该示例生成一个倒置图表,其中条形图连接到x轴的顶部。

Upside-down

<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
  var w = 500;
  var h = 300;

  var dataset = [[ { x: 0, y: 5 }, { x: 1, y: 4 }, { x: 2, y: 2 }, { x: 3, y: 7 }, { x: 4, y: 23 }],
    [ { x: 0, y: 10 }, { x: 1, y: 12 }, { x: 2, y: 19 }, { x: 3, y: 23 }, { x: 4, y: 17 } ],
    [ { x: 0, y: 22 }, { x: 1, y: 28 }, { x: 2, y: 32 }, { x: 3, y: 35 }, { x: 4, y: 43 } ]];

  var stack = d3.layout.stack();
  stack(dataset);

  var xScale = d3.scale.ordinal()
      .domain(d3.range(dataset[0].length)).rangeRoundBands([0, w], 0.05);

  var yScale = d3.scale.linear()
      .domain([0, d3.max(dataset, function(d) {
        return d3.max(d, function(d) { return d.y0 + d.y; });
      })])
      .range([0, h]);

  var colors = d3.scale.category10();

  var svg = d3.select("body").append("svg").attr("width", w).attr("height", h);

  var groups = svg.selectAll("g").data(dataset).enter().append("g")
      .style("fill", function(d, i) { return colors(i); });

  var rects = groups.selectAll("rect")
      .data(function(d) { return d; })
      .enter()
      .append("rect")
      .attr("x", function(d, i) { return xScale(i); })
      .attr("y", function(d) { return yScale(d.y0); })
      .attr("height", function(d) { return yScale(d.y); })
      .attr("width", xScale.rangeBand());
</script>

这是使堆叠条倒置的代码。

当我更改以下几个代码时:

1)从:

更改yScale .range
.range([0, h]);

.range([h, 0]);

2)更改矩形“y”.attr:

.attr("y", function(d) { return yScale(d.y0); })

.attr("y", function(d) { return yScale(d.y0) + yScale(d.y) - h; })

3)从:

更改rect“height”.attr
.attr("height", function(d) { return yScale(d.y); })

.attr("height", function(d) { return h - yScale(d.y); })

应用这些更改后,堆栈会附加到底部并仍然保持其相对大小。 right graph

问题是,我没有理解第二步和第三步的含义。

为什么y应为yScale(d.y0) + yScale(d.y) - h

为什么height应该h - yScale(d.y)

如果将这些值修改为不同的值(例如y(yScale(d.y0) + yScale(d.y))/10左右),则不会显示所需的图表。

1 个答案:

答案 0 :(得分:1)

这个&#34;反向数学的原因&#34; (正如Scott Murray在他的代码中所说的那样)在你的第一个代码中,颠倒的代码,SVG坐标系统和范围都有Y坐标从上到下增长(零位于顶部,最大值位于底部)。但是当您在第二个代码中将范围反转为([h, 0])时,SVG坐标系继续使Y坐标从上到下继续增长,尽管范围现在向上。

在&#34;颠倒&#34;代码,栏的顶部实际上是它的基础,它的高度与SVG系统一起下降。但在第二个代码中,&#34;正常&#34;事情更复杂:&#34; base&#34;酒吧不是它的&#34; y&#34;属性不再,高度值向下添加像素,无论反转范围如何。 SVG的坐标系统不会因为我们反转范围而自动反转。

这很复杂,所以让我重新说一下:在SVG坐标系统中,&#34; y&#34;属性始终是矩形的顶部。在第一个代码中,矩形的顶部是条形的底部...但是,在第二个代码中,矩形的顶部是条形的顶部。令我感到困惑,我知道。

让我们做一个简单的数学运算:设想一个高度为100像素的SVG和一个高度为80像素的单条(y0:0,y:80)。画这个吧,&#34; y&#34;属性必须设置其顶部。怎么计算呢? yScale(d.y0)给了我们100,而yScale(d.y)给了我们20.通过添加它们,我们有120,减去100(高度)给我们20,顶部的位置。为什么不直接使用d.y?它可以用于第一个栏,但它不会用于后续栏。

现在高度,必须是80像素。 yScale(d.y)给了我们20,所以,100(身高)减20给我们80 ......这对每个酒吧来说都是如此。