Search code examples
d3.jssvgalignmentaxes

FreeCodeCamp.org d3 bar chart axis alignment test is failing


I'm doing a d3 bar char project for FreeCodeCamp and the problem is that the bars are not aligning with the ticks on the x-axis.

The issue is that how the bars are off is not consistent from tick to tick, and some of them even seem to be aligned.

After doing some research, I thought it might be an issue with the fact that I didn't necessary set the numbers of ticks so that the number of bars is an even multiple, so I tried that with xAxis.ticks(data.length/25);, and that didn't fix it. Then I figured I'd try a multiple of four, since the data is broken up into one data point per quarter (xAxis.ticks(16);), and that didn't work either.

The weird thing is that the scale for the x-axis is the same scale used for the positioning of the bars. The data is pulled from a JSON request

Here's the JSON request:

var req = new XMLHttpRequest();
  req.open('GET', 'https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json',true);
  req.send();
req.onload=function(){
    let data = JSON.parse(req.responseText).data.map(e=>{
      return {
        gdp: e[1],
        date: new Date(Date.parse(e[0])),
        dateString: e[0],
        dateInt: Date.parse(e[0])
      };
    });

This is the x scale I'm using:

const xScale = d3.scaleLinear()
    .domain(
      [
        d3.min(data, d=>d.dateInt), 
        d3.max(data, d=>d.dateInt)
      ]
    )
    .range([padding, width-padding]);

The x attribute declaration for the bars is .attr('x', (d,i)=>xScale(d.dateInt))

and finally the code segment for the axes declaration:

var xAxis = d3.axisBottom(xScale);
    xAxis.ticks(16);
    xAxis.tickFormat(d3.timeFormat("%Y"));

the width variable is the width of the entire svg element, and padding is the amount of padding around the actual graph area.

And here is the g element wrapping the axis:

svg.append('g')
    .attr('transform', `translate(0, ${height-padding})`)
    .attr('id', 'x-axis')
    .call(xAxis);

Where height is the height of the svg element.

In case it's relevant, which I don't think it is because the x position for the rects are defined explicitly, but the width of the bars is defined as const barWidth = (width-2*padding)/data.length;

Honestly, I don't care if the bars are to the left, the middle, or the right of the ticks, because that can always be adjusted as long as it's consistent, but since it's not even consistent where the bars are landing in relation to the ticks, I'm not sure where to go at this point.

Just to note, if you fork the project and change the line near the top of the JS code from const width = 900; to const width = 9000; it will increase the width of the entire svg element and its child elements with width attributes (specifically the individual bars), making it easier to see where the bars line up in relation to the tick marks.


Solution

  • So after a week of playing around with the number of tick marks and the alignment of the axis, I found out I needed to switch from scaleLinear to scaleTime