Wrong usage of d3 scale with same values in data?

client-side, d3.js, html, javascript, svg

Solution

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());

Problem

I'm new to d3 and using it for creating a simple chart using array of numbers where the value '16' appears twice in it. It generate the chart with one 'missing' 'rect' element for the 2nd '16' value, when I check the html I see that both '16' rect has same 'y' value of 72. Please tell me what I'm doing wrong, thanks code: ``` var data = [4, 8, 15, 16, 23, 16]; var chart = d3.select("body").append("svg") .attr("class", "chart") .attr("width", 420) .attr("height", 20 * data.length); var x = d3.scale.linear() .domain([0, d3.max(data)]) .range([0, 420]) var y = d3.scale.ordinal() .domain(data) .rangeBands([0, 120]); chart.selectAll("rect") .data(data) .enter().append("rect") .attr("y", y) .attr("width", x) .attr("height", y.rangeBand()); ```

Original source