我在d3.js中绘制了我的第一个条形图,并且对scaleLinear()对条形位置的影响感到非常惊讶。
首先我将比例定义为:
var y = d3.scaleLinear()
.domain([0,100])
.range([0,300]);
实际上,域名太大,20就足够了。所以我设置:
var y = d3.scaleLinear()
.domain([0,20])
.range([0,300]);
条形较长,这是正确的,但它们被推下来,但事实并非如此。以下是嵌入Ruby on Rails 5.0部分的完整脚本。
有人可以解释这种行为并帮我解决问题吗?
非常感谢。
完整的脚本:
<script>
// Progression data
var errors = <%= d3_chart_series_for(this_object).map { |measure| {index: measure.idx, count: measure.score}}.to_json.html_safe %>;
// Returns an array of hashes
// var errors = [{"index":"2017-01-14","count":"5.35"},{"index":"2017-01-15","count":"2.24"},{"index":"2017-01-16","count":"1.55"},{"index":"2017-01-17","count":"5.11"},{"index":"2017-01-18","count":"2.96"},{"index":"2017-01-19","count":"4.62"},{"index":"2017-01-20","count":"6.71"},{"index":"2017-01-21","count":"9.47"},{"index":"2017-01-22","count":"8.15"},{"index":"2017-01-23","count":"9.25"},{"index":"2017-01-24","count":"5.35"}];
var x = d3.scaleTime()
.domain([
new Date(Date.parse('<%=history_date.strftime("%Y-%m-%d")%>')),
new Date()
])
.range([0,500]);
var y = d3.scaleLinear()
.domain([0,100])
.range([0,300]);
var xAxis = d3.axisTop(x)
.ticks(10);
var yAxis = d3.axisRight(y)
.ticks(5);
var graph = d3.select('#progression')
.append('svg')
.attr('width', 650)
.attr('height', 400);
var bars = graph.selectAll('rect')
.data(errors);
var newBars = bars.enter();
graph.append('g')
.attr('class', 'x axis')
.attr("transform", "translate(100,50)")
.call(xAxis);
graph.append('g')
.attr('class', 'y axis')
.attr("transform", "translate(600,50)")
.call(yAxis);
newBars.append('rect')
.attr("transform", "translate(100,0)")
.attr('x',function(d, i) {
return x(Date.parse(d.index));})
.attr('y',y(20))
.attr('height', function(d,i) {
return y(d.count);})
.attr('width', 20 )
.attr('fill', d3.scale.category20());
</script>
答案 0 :(得分:1)
这是问题所在:
.attr('y',y(20))
当您执行此操作以设置条形的y
位置时,您未定义固定位置,而是根据域而变化的位置。因此,每次更改域名时,y(20)
都会映射到范围内的其他值。
检查一下:
var y = d3.scaleLinear()
.domain([0, 100])
.range([50, 300]);
console.log(y(20));//returns 100
var y = d3.scaleLinear()
.domain([0, 20])
.range([50, 300]);
console.log(y(20));//returns 300
解决方案:将条形的顶部设置为x轴的相同y位置,在代码中为50:
.attr('y', 50)
如果你想要填充,只需在该值上添加一些东西。
这是一个演示,y域从0到20,如您所要求的那样:
var errors = [{"index":"2017-01-14","count":"5.35"},{"index":"2017-01-15","count":"2.24"},{"index":"2017-01-16","count":"1.55"},{"index":"2017-01-17","count":"5.11"},{"index":"2017-01-18","count":"2.96"},{"index":"2017-01-19","count":"4.62"},{"index":"2017-01-20","count":"6.71"},{"index":"2017-01-21","count":"9.47"},{"index":"2017-01-22","count":"8.15"},{"index":"2017-01-23","count":"9.25"},{"index":"2017-01-24","count":"5.35"}];
var parse = d3.timeParse("%Y-%m-%d");
errors.forEach(function(d){
d.index = parse(d.index);
});
var x = d3.scaleTime()
.domain(d3.extent(errors, function(d){ return d.index}))
.range([0,500]);
var y = d3.scaleLinear()
.domain([0,20])
.range([50,300]);
var xAxis = d3.axisTop(x)
.ticks(10);
var yAxis = d3.axisRight(y)
.ticks(5);
var graph = d3.select('body')
.append('svg')
.attr('width', 650)
.attr('height', 400);
var bars = graph.selectAll('rect')
.data(errors);
var newBars = bars.enter();
graph.append('g')
.attr('class', 'x axis')
.attr("transform", "translate(100,50)")
.call(xAxis);
graph.append('g')
.attr('class', 'y axis')
.attr("transform", "translate(600,50)")
.call(yAxis);
newBars.append('rect')
.attr("transform", "translate(100,0)")
.attr('x',function(d) {
return x(d.index);})
.attr('y', 50)
.attr('height', function(d,i) {
return y(d.count);})
.attr('width', 20 )
.attr('fill', "teal");
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
PS :条形图和时间刻度不能很好地混合......你可以看到条纹在精确的日期开始,但它们的宽度使得他们在错误的日期完成。将它们移到左侧,或者更好的选择,使用另一个比例(作为带尺)。