Reputation: 121
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.axis path {
fill: none;
stroke: #777;
shape-rendering: crispEdges;
}
.axis text {
font: 10px sans-serif;
}
</style>
</head>
<body>
<svg id="visualization" width="1000" height="500"></svg>
</body>
</html>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
function InitChart() {
var data = [{
"sale": "215",
"calendarDate": "20140302"
}, {
"sale": "179",
"calendarDate": "20140303"
}, {
"sale": "199",
"calendarDate": "20140304"
}, {
"sale": "134",
"calendarDate": "20140305"
}, {
"sale": "176",
"calendarDate": "20140306"
}];
var vis = d3.select("#visualization"),
WIDTH = 1000,
HEIGHT = 500,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 50
},
calendarDatesAsStrings = ['02.03.2014','03.03.2014','04.03.2014','05.03.2014','06.03.2014'],
xScale = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([20140302, 20140306]),
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([124, 225]),
xAxis = d3.svg.axis().scale(xScale),
yAxis = d3.svg.axis().scale(yScale).orient("left");
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis)
.selectAll('text')
.text(function (d, i) { return calendarDatesAsStrings[i]; });
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var lineGen = d3.svg.line()
.x(function(d) {
return xScale(d.calendarDate);
})
.y(function(d) {
return yScale(d.sale);
});
vis.append('svg:path')
.attr('d', lineGen(data))
.attr('stroke', 'green')
.attr('stroke-width', 2)
.attr('fill', 'none');
}
InitChart();
</script>
http://jsbin.com/zupejizeho/1/edit
I expected the labels to be in their right positions, they aren't.
Instead, they look like they are "compressed" and placed every half-segment instead of full segment.
What am I doing wrong?
Upvotes: 0
Views: 380
Reputation: 108522
You have a decision to make here. Treat your dates as strings and use an ordinal scale or you treat your dates as dates and use a time scale. Right now you are using a linear scale which does not map nicely to date stamps.
Since your dataset is pretty limited an ordinal scale is probably easier:
// map all my dates to an ordinal
// with points separated nicely in my range
xScale = d3.scale.ordinal()
.rangePoints([MARGINS.left, WIDTH - MARGINS.right])
.domain(data.map(function(d){ return d.calendarDate })),
And format the date strings:
// then reformat the strings to what you want with some format helpers
oldFormat = d3.time.format("%Y%m%d"),
newFormat = d3.time.format("%m.%d.%Y");
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(d){
var dateTime = oldFormat.parse(d); // parse the string to date
return newFormat(dateTime); // format it back to appropriate string
}),
Updated example here.
If you get a little more data complexity, you'll probably want to shift to really treating your dates as dates. So, first, fix your data:
data = data.map(function(d){
return {
sale: +d.sale, // this is really a numeric
calendarDate: oldFormat.parse(d.calendarDate) // this be a datetime now
}
});
Set up your scale with time:
xScale = d3.time.scale()
.range([MARGINS.left, WIDTH - MARGINS.right])
.domain(
[d3.min(data.map(function(d){ return d.calendarDate })),
d3.max(data.map(function(d){ return d.calendarDate }))]
),
And the format becomes simpler:
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(d3.time.format("%m.%d.%Y")),
Here an example of this.
Upvotes: 1
Reputation: 1522
you don't need to add the last two rows after the call of the xAxis, here:
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis)
.selectAll('text')
.text(function (d, i) { return calendarDatesAsStrings[i]; });
you simply have to call the xAxis
and that's it, working link: http://jsbin.com/yabecihihi/1/edit?html,output (the dates need to be parsed properly with a time scale tho)
Upvotes: 0