如何在带有scaleTime的条形图中使用x和宽度? [英] How to use x and width in a bar chart with scaleTime?
问题描述
我这里有一个codepen - https://codepen.io/anon/pen / xpaYYw?editors = 0010
它是一个简单的测试图,但日期的格式如下。
我在x轴上有日期,在y上有金额
如何使用x刻度来设置条形的宽度和x位置。 / p>
layers.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('height',function(d,i){
返回高度 - y(d.one);
} )
.attr('y',函数(d,i){
返回y(d.one);
})
。 attr('width',function(d,i){
return 50;
})
.attr('x',function(d,i){
返回80 * i;
})
.style('fill',(d,i)=> {
返回颜色[i];
});
您的问题与编程无关,或JavaScript,或D3 ...问题是一个基本的dataviz概念(这就是为什么我添加数据可视化标记在你的问题中):
你要做的事情是不正确的!您应该不使用带有时间刻度的条形图。时间尺度用于时间序列(我们使用点或线连接的点)。
如果你在x轴上使用带时间的条,你将面临问题:
- 定位栏:栏的左边距始终为您设置的日期。整个栏将在之后;
- 设置栏的宽度:在实际条形图中,使用分类对于x轴的变量,宽度没有任何意义。但在时间范围内,宽度代表时间。
然而,仅仅为了解释,让我们使用时间刻度创建此条形图(尽管这是错误的选项)...以下是如何执行此操作:
首先,在时间中设置条形的宽度。比方说,每个条的宽度为10天:
.attr(width,function(d){
返回x(d3.timeDay.offset(d.date,10)) - x(d.date)
})
然后,将栏的 x
位置设置为当前日期半其宽度(即,在我们的例子中少于5天):
.attr('x',function(d,i){
return x(d3.timeDay.offset(d.date,-5));
})
最后,不要忘记在时间刻度中创建填充:
var x = d3。 scaleTime()
.domain([d3.min(data,function(d){
return d3.timeDay.offset(d.date,-10);
}),d3。 max(data,function(d){
return d3.timeDay.offset(d.date,10);
})])
.range([0,width]);
以下是包含这些更改的代码:
var keys = []; var legendKeys = []; var maxVal = []; var w = 800; var h = 450; var margin = {top:30,bottom:40,left:50,right:20,}; var width = w - margin.left - margin.right; var height = h - margin.top - margin .bottom; var colors = ['#FF9A00','#FFEBB6','#FFC400','#B4EDA0','#FF4436']; var data = [{one:4306,two:2465, 三:2299,四:988,五:554,六:1841,日期:2015-05-31T00:00:00},{一:4378,两个:2457,三:2348,四:1021,五:498,六:1921,日期:2015-06-30T00:00:00},{一: 3404,两个:2348,三:1655,四:809,五:473,六:1056, date:2015-07-31T00:00:00},]; data.forEach(function(d){d.date = new Date(d.date)})for(var i = 0;我< data.length; i ++){for(var key in data [i]){if(!data.hasOwnProperty(key)&& key!==date)maxVal.push(data [i] [key]); var x = d3.scaleTime()。domain([d3.min(data,function(d){return d3.timeDay.offset(d.date,-10);}),d3.max(data,function (d){return d3.timeDay.offset(d.date,10);})])。range([0,width]); var y = d3.scaleLinear()。domain([0,d3.max( maxVal,function(d){return d;})])。range([height,0]); var svg = d3.select('body')。append('svg')。attr('class',' chart')。attr('width',w).attr('height',h); var chart = svg.append('g')。classed('graph',true).attr('transform',' translate('+ margin.left +','+ margin.top +')'); var layersArea = chart.append('g')。attr('class','layers'); var layers = layersArea.append ('g')。attr('class','layer'); layers.selectAll('rect')。data(data).enter()。append('rect')。attr('height',function( d,i){return height - y(d.one);})。attr('y',function(d,i){return y(d.one);})// .attr('width', function(d,i){// return 50; //})。attr(width,fun ction(d){return x(d3.timeDay.offset(d.date,10)) - x(d.date)})。attr('x',function(d,i){return x(d3.timeDay) .offset(d.date,-5));})。style('fill',(d,i)=> {return colors [i];}); chart.append('g').classed('x axis',true).attr(transform,translate(0,+ height +))。call (d3.axisBottom(x).tickFormat(d3.timeFormat(%Y-%m-%d))。tickValues(data.map(function(d){return new Date(d.date)}))) ; chart.append('g').classed('y axis',true).call(d3.axisLeft(y).ticks(10));
< pre class =snippet-code-html lang-html prettyprint-override> < script src =https://d3js.org/d3.v4.min.js>< /脚本>
I have a codepen here - https://codepen.io/anon/pen/xpaYYw?editors=0010
Its a simple test graph but the date will be formatted like this.
I have dates on the x axis and amounts on the y
How can I use the x scale to set the width and x position of the bars.
layers.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('height', function(d, i) {
return height - y(d.one);
})
.attr('y', function(d, i) {
return y(d.one);
})
.attr('width', function(d, i) {
return 50;
})
.attr('x', function(d, i) {
return 80*i;
})
.style('fill', (d, i) => {
return colors[i];
});
The problem with your question has nothing to do with programming, or JavaScript, or D3... the problem is a basic dataviz concept (that's why I added the data-visualization tag in your question):
What you're trying to do is not correct! You should not use bars with a time scale. Time scales are for time series (in which we use dots, or dots connected by lines).
If you use bars with time in the x axis you'll face problems:
- Positioning the bar: the left margin of the bar will be always at the date you set. The whole bar will lie after that date;
- Setting the width of the bar: in a real bar chart, which uses categorical variables for the x axis, the width has no meaning. But in a time scale the width represents time.
However, just for the sake of explanation, let's create this bar chart with a time scale (despite the fact that this is a wrong choice)... Here is how to do it:
First, set the "width" of the bars in time. Let's say, each bar will have 10 days of width:
.attr("width", function(d){
return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})
Then, set the x
position of the bar to the current date less half its width (that is, less 5 days in our example):
.attr('x', function(d, i) {
return x(d3.timeDay.offset(d.date, -5));
})
Finally, don't forget to create a "padding" in the time scale:
var x = d3.scaleTime()
.domain([d3.min(data, function(d) {
return d3.timeDay.offset(d.date, -10);
}), d3.max(data, function(d) {
return d3.timeDay.offset(d.date, 10);
})])
.range([0, width]);
Here is your code with those changes:
var keys = [];
var legendKeys = [];
var maxVal = [];
var w = 800;
var h = 450;
var margin = {
top: 30,
bottom: 40,
left: 50,
right: 20,
};
var width = w - margin.left - margin.right;
var height = h - margin.top - margin.bottom;
var colors = ['#FF9A00', '#FFEBB6', '#FFC400', '#B4EDA0', '#FF4436'];
var data = [{
"one": 4306,
"two": 2465,
"three": 2299,
"four": 988,
"five": 554,
"six": 1841,
"date": "2015-05-31T00:00:00"
}, {
"one": 4378,
"two": 2457,
"three": 2348,
"four": 1021,
"five": 498,
"six": 1921,
"date": "2015-06-30T00:00:00"
}, {
"one": 3404,
"two": 2348,
"three": 1655,
"four": 809,
"five": 473,
"six": 1056,
"date": "2015-07-31T00:00:00"
},
];
data.forEach(function(d) {
d.date = new Date(d.date)
})
for (var i = 0; i < data.length; i++) {
for (var key in data[i]) {
if (!data.hasOwnProperty(key) && key !== "date")
maxVal.push(data[i][key]);
}
}
var x = d3.scaleTime()
.domain([d3.min(data, function(d) {
return d3.timeDay.offset(d.date, -10);
}), d3.max(data, function(d) {
return d3.timeDay.offset(d.date, 10);
})])
.range([0, width]);
var y = d3.scaleLinear()
.domain([0, d3.max(maxVal, function(d) {
return d;
})])
.range([height, 0]);
var svg = d3.select('body').append('svg')
.attr('class', 'chart')
.attr('width', w)
.attr('height', h);
var chart = svg.append('g')
.classed('graph', true)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
var layersArea = chart.append('g')
.attr('class', 'layers');
var layers = layersArea.append('g')
.attr('class', 'layer');
layers.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('height', function(d, i) {
return height - y(d.one);
})
.attr('y', function(d, i) {
return y(d.one);
})
// .attr('width', function(d, i) {
// return 50;
// })
.attr("width", function(d) {
return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})
.attr('x', function(d, i) {
return x(d3.timeDay.offset(d.date, -5));
})
.style('fill', (d, i) => {
return colors[i];
});
chart.append('g')
.classed('x axis', true)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%Y-%m-%d")).tickValues(data.map(function(d) {
return new Date(d.date)
})));
chart.append('g')
.classed('y axis', true)
.call(d3.axisLeft(y)
.ticks(10));
<script src="https://d3js.org/d3.v4.min.js"></script>
这篇关于如何在带有scaleTime的条形图中使用x和宽度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!