The problem with your code is that you are trying to use the values from your data
array to create range bands on an ordinal scale. Since the same input value will always be mapped to the same output value that means that both inputs 16
get mapped to the same range band 72
.
If you want each input value to be mapped to its own "bar" then you need to use array indices instead of array values.
First you prepare the indices
var indices = d3.range(0, data.length); // [0, 1, 2, ..., data.length-1]
Then you use them to define the y
scale domain
var y = d3.scale.ordinal()
.domain(indices)
// use rangeRoundBands instead of rangeBands when your output units
// are pixels (or integers) if you want to avoid empty line artifacts
.rangeRoundBands([0, chartHeight]);
Finally, instead of using array values as inputs use array indices when mapping to y
chart.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("y", function (value, index) {
// use the index as input instead of value; y(index) instead of y(value)
return y(index);
})
.attr("width", x)
.attr("height", y.rangeBand());
As an added bonus this code will automatically rescale the chart if the amount of data changes or if you decide to change the chart width or height.
Here's a jsFiddle demo: http://jsfiddle.net/q8SBN/1/
Complete code:
var data = [4, 8, 15, 16, 23, 16];
var indices = d3.range(0, data.length);
var chartWidth = 420;
var chartHeight = 120;
var chart = d3.select("body").append("svg")
.attr("class", "chart")
.attr("width", chartWidth)
.attr("height", chartHeight);
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, chartWidth])
var y = d3.scale.ordinal()
.domain(indices)
.rangeRoundBands([0, chartHeight]);
chart.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("y", function (value, index) { return y(index); })
.attr("width", x)
.attr("height", y.rangeBand());