我需要创建一个可以有负值的d3条形图。理想情况下,应该根据数据的范围计算轴零点位置,但我会建议采用假设对称正负范围的解决方案,即它始终位于图表中间。
I need to create a d3 bar chart that can have negative values. Ideally the axis zero position should be calculated based on the extent of the data, but I'd settle for a solution that assumes symmetric positive and negative extent, i.e. that it would be always in the middle of the chart.
这里是我想要实现的示例。
Here's an example of what I'd like to achieve.
推荐答案
数组数组,这包括一些正值和负值:
OK, let's say you have an array of numbers as your dataset, and this includes some positive and negative values:
var data = [-15, -20, -22, -18, 2, 6, -26, -18];您将需要两个尺度来构建条形图。您需要一个定量标尺(通常是线性标尺)来计算沿着 x 轴和第二个顺序量表来计算栏沿着 y轴的位置。
You'll want two scales to construct a bar chart. You need one quantitative scale (typically a linear scale) to compute the bar positions along the x-axis, and a second ordinal scale to compute the bar positions along the y-axis.
对于量化比例,您通常需要计算数据的域,它基于最小值和最大值。一个简单的方法是通过 d3.extent :
For the quantitative scale, you typically need to compute the domain of your data, which is based on the minimum and maximum value. An easy way to do that is via d3.extent:
var x = d3.scale.linear() .domain(d3.extent(data)) .range([0, width]);您可能还需要 nice 缩放到一定程度。作为另一个例子,有时你希望零值在画布的中间居中,在这种情况下,您需要采取最大和最大值的较大值:
You might also want to nice the scale to round the extent slightly. As another example, sometimes you want the zero-value to be centered in the middle of the canvas, in which case you'll want to take the greater of the minimum and maximum value:
var x0 = Math.max(-d3.min(data), d3.max(data)); var x = d3.scale.linear() .domain([-x0, x0]) .range([0, width]) .nice();或者,您可以对任何所需的域进行硬编码。
Alternatively, you can hard-code whatever domain you want.
var x = d3.scale.linear() .domain([-30, 30]) .range([0, width]);对于 y 轴,您需要使用 rangeRoundBands 将垂直空间划分为每个条的带。这也允许您指定条形之间的填充量。通常,序数量表与一些标识数据(例如名称或唯一ID)一起使用。但是,您也可以使用顺序标度结合数据的索引:
For the y-axis, you'll want to use rangeRoundBands to divide the vertical space into bands for each bar. This also lets you specify the amount of padding between bars. Often an ordinal scale is used with some identifying data—such as a name or a unique id. However, you can also use ordinal scales in conjunction with the data's index:
var y = d3.scale.ordinal() .domain(d3.range(data.length)) .rangeRoundBands([0, height], .2);既然你有两个尺度,你可以创建rect元素来显示条形。一个棘手的部分是,在SVG中,rects基于它们的顶层定位( x 和 y 属性)左角。因此,我们需要使用 x 和 y 标尺来计算左上角的位置,这取决于关联值是正还是负:如果值为正,则数据值确定条的右边缘,而如果它为负,则确定条的左边缘。因此,这里的条件:
Now that you've got your two scales, you can create the rect elements to display the bars. The one tricky part is that in SVG, rects are positioned (the x and y attributes) based on their top-left corner. So we need to use the x- and y-scales to compute the position of the top-left corner, and that depends on whether the associated value is positive or negative: if the value is positive, then the data value determines the right edge of the bar, while if it's negative, it determines the left edge of the bar. Hence the conditionals here:
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());最后,您可以添加轴以在顶部显示刻度线。您还可以计算填充样式(或甚至渐变)以更改区分正值和负值的外观。将它们放在一起:
Lastly, you can add an axis to display tick marks on top. You might also compute a fill style (or even a gradient) to alter the differentiate the appearance of positive and negative values. Putting it all together:
- 带有负值的条形图
- Bar Chart with Negative Values
更多推荐
具有负值的条形图
发布评论