Pregunta

I am working on a d3 chart that uses a time.scale and rects and I am stuck on a very small issue. Either the x axis is not extending the full length of its svg container (so the x axis is not under that last bar) or the x position of the rects is somehow not properly taking the range into account. I have tried looking through several examples and many stackoverflow posts but so far I can't figure out where I've screwed up. Thank you!

Here is my code:

var margin = {top:30, right:30, bottom:30, left:30},
    width = 600 - margin.right - margin.left,
    height = 300 - margin.top - margin.bottom;  


var parseDate =  d3.time.format("%d-%b-%y").parse;

var formatTime = d3.time.format("%e %B");                 


var x = d3.time.scale().range([0, width]);

var y = d3.scale.linear().range([height, 0]);



var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickFormat(d3.time.format("%b %y"));                       


var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left")
            .ticks(5);  

var svg = d3.select("body").append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height",height + margin.top + margin.bottom)
            .append("g")
            .attr("transform" , "translate(" + margin.left + "," + margin.top + ")");





d3.tsv("data/months.tsv", function(error, data) {
data.forEach(function(d) {
        d.month =  parseDate(d.month);
        d.value = +d.value;  //ensures variable is treated like a number

    }); 


   x.domain(d3.extent(data, function(d) { return d.month; }));
   y.domain([0,d3.max(data,function(d) { return d.value; })]);

   var barPadding = 4;

   var barWidth = width/data.length - barPadding;

   var rects = svg.selectAll("rect")
                .data(data)
                .enter().append("rect")
                .attr("class" , "bar")
                .attr("x", function(d) { return x(d.month); })  // I think the problem is here
                .attr("y", function(d) { return y(d.value); })  
                .attr("width", barWidth )   
                .attr("height", function(d) { return height - y(d.value); });           



    svg.append("g")
            .attr("class", "axis")
            .attr("transform","translate(0, " + height + ")")
            .call(xAxis);

            svg.append("g")
            .attr("class" , "axis") 
            .call(yAxis);                   

});

Thank you in advance!

¿Fue útil?

Solución

The problem is that you're starting the bars at the position of the ticks. That is, the left hand side of the bar is aligned with the respective tick, creating the impression that the bar isn't aligned because it is off center.

To fix, simply subtract barWidth/2 as an offset to the x position of the bars. You'll also want to adjust the output range of your x scale such that the y axis and the first bar don't overlap.

x.range([barWidth/2, width]);
// etc.
rects.attr("x", function(d) { return x(d.month) - barWidth/2; })

Complete example here.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top