admin管理员组文章数量:1279145
I have a codepen here -
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];
});
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];
});
Share
Improve this question
edited Jan 16, 2018 at 10:54
Gerardo Furtado
102k9 gold badges128 silver badges177 bronze badges
asked Jan 16, 2018 at 10:22
ttmtttmt
4,98431 gold badges113 silver badges167 bronze badges
2 Answers
Reset to default 9The 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/d3.v4.min.js"></script>
Regardless of what Gerardo is saying, I partially agree, because sometimes you want to pare monthly data which can be categorical.
For this purposes 2 scales need to be defined, 1 is scaleTime()
and then scaleBand which has range dependant on scaleTime()
output.
xTime = d3.scaleTime().range([0, WIDTH]).domain([minDate, maxDate]);
xScale = d3
.scaleBand()
.range([0, WIDTH])
.domain(d3.timeMonth.range(...xTime.domain()));
in this example I used minDate, maxDate in case you want to display 6 months of data regardless if data actually has said data or not, otherwise extent()
can be used to get min and max values.
Good thing about this approach is that is dynamic and missing values will display no data, however space will be dedicated to it.
本文标签: javascriptHow to use x and width in a bar chart with scaleTimeStack Overflow
版权声明:本文标题:javascript - How to use x and width in a bar chart with scaleTime? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741296825a2370864.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论