带负值的条形图

时间:2012-04-12 16:04:10

标签: d3.js

我需要创建一个可以有负值的d3条形图。理想情况下,轴零位置应根据数据的范围进行计算,但我会考虑采用对称正负范围的解决方案,即它始终位于图表的中间位置。

以下是我想要实现的一个例子。

Bar chart with negative values

1 个答案:

答案 0 :(得分:54)

好的,假设您有一组数字作为数据集,这包括一些正面和负面的值:

var data = [-15, -20, -22, -18, 2, 6, -26, -18];

您需要两个比例来构建条形图。您需要一个定量比例(通常为linear scale)来计算 x 轴上的柱位置,并需要第二个ordinal scale来计算沿着的柱位置ÿ轴摆动。

对于定量比例,您通常需要计算数据的域,该域基于最小值和最大值。一种简单的方法是通过d3.extent

var x = d3.scale.linear()
    .domain(d3.extent(data))
    .range([0, width]);

您可能还希望nice缩放以略微缩小范围。作为另一个例子,有时您希望零值在画布中间居中,在这种情况下,您需要获取最小值和最大值中的较大值:

var x0 = Math.max(-d3.min(data), d3.max(data));

var x = d3.scale.linear()
    .domain([-x0, x0])
    .range([0, width])
    .nice();

或者,您可以对您想要的任何域进行硬编码。

var x = d3.scale.linear()
    .domain([-30, 30])
    .range([0, width]);

对于 y -axis,您需要使用rangeRoundBands将垂直空间划分为每个条形的条带。这也允许您指定条形之间的填充量。通常,序数量表与一些识别数据一起使用 - 例如名称或唯一ID。但是,您也可以将序数比例与数据索引结合使用:

var y = d3.scale.ordinal()
    .domain(d3.range(data.length))
    .rangeRoundBands([0, height], .2);

现在您已经拥有了两个比例,您可以创建矩形元素来显示条形图。一个棘手的部分是,在SVG中,rects根据其左上角定位(xy属性)。所以我们需要使用 x - 和 y -scales来计算左上角的位置,这取决于相关值是正还是负:如果值为正,则数据值确定条的右边缘,而如果值为负,则确定条的左边缘。因此这里有条件:

svg.selectAll(".bar")
    .data(data)
  .enter().append("rect")
    .attr("class", "bar")
    .attr("x", function(d, i) { return x(Math.min(0, d)); })
    .attr("y", function(d, i) { return y(i); })
    .attr("width", function(d, i) { return Math.abs(x(d) - x(0)); })
    .attr("height", y.rangeBand());

最后,您可以添加一个轴以在顶部显示刻度线。您还可以计算填充样式(甚至是渐变)以更改区分正值和负值的外观。把它们放在一起: