我试图从包含2个值的简单数据集中创建一个非常简单的堆叠水平条形图。
我想分别在条形图的左侧和右侧显示数据集值。 <svg>
是500px宽,我想
要显示的图表从100到400,以便我可以在条形图之前和之后容纳<text>
。为此,我试图缩小范围
从[0,500]到[100,400],但结果不符合预期。
我还想在不使用layout.stack()的情况下绘制图表,以便我可以使用像[66852,7550]这样的简单数据集
这是Fiddle
//Width and height
var w = 500;
var h = 60;
//Original data
//var dataset = [66852, 7550]
//changed to below to support layout.stack()
var dataset = [ [{y:66852}], [{y:7550}] ];
//Set up stack method
var stack = d3.layout.stack();
//Data, stacked
stack(dataset);
//Set up scales
var xScale = d3.scale.linear()
.domain([0, d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([100, 400]);
var yScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([0, h], 0.05);
//Easy colors accessible via a 10-step ordinal scale
var colors = d3.scale.category10();
//Create SVG element
var svg = d3.select(".chart")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.style("fill", function(d, i) {
return colors(i);
});
// Add a rect for each data value
var rects = groups.selectAll( 'rect' )
.data( function( d ) { return d; } )
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(d.y0);
})
.attr("y", function(d, i) {
console.log('y: '+yScale(i));
return yScale(i);
})
.attr("width", function(d) {
console.log('width: '+xScale(d.y));
return xScale(d.y);
})
.attr("height", 10);
答案 0 :(得分:2)
问题是,尽管它的名称,你的线性xScale
不是线性的(0的图像是100)。因此,当您使用return xScale(d.y);
作为宽度时,您将为每个矩形的宽度添加100(在数学术语中,使用的函数是xScale(z)= 0.00211 * z + 100:这是仿射,而不是线性)。
编辑,示例:
=&GT;对于宽度和x位置,不可能直接使用相同的比例。因此,要么使用不同的函数来计算宽度和x,要么使用额外的transform
来欺骗x(请参阅下面的原始解决方案)。
最简单的解决方案是range
[0,300]
(而不是[100,400]
),并将绘图区域放在g
.attr("transform", "translate(100,0)")
之内以情节为中心。
第二个选项(听起来像你喜欢的那个):使用xScale(d.y0+d.y) - xScale(d.y0)
作为宽度(而不只是xScale(d.y)
)。这直接计算左右端点之间的距离,即它给出宽度。它应该适用于任何比例(不一定是线性的)。
至于你的第二个问题,我真的不知道另外一般的做法(除了编写你自己的绘图程序,它不会太难)。但您可以轻松地将简单数组转换为适合布局的数组:
var dataset = [66852, 7550]
var layoutDataset = dataset.map(function(d){ return [{y:d}] });