D3 Bar Chart: Struggling to customize Date ticks

Heya,

I’m losing my mind over finishing my first D3 project to visualize the US GDP bar chart (https://codepen.io/spreeni/pen/bQwoGN). I can’t get my x-axis to display just ticks for every 5 years or so. Right now it just takes the automatically chosen ticks and they’re not very pretty. Two of the test cases also keep failing, apparently

  • The bar elements’ “data-date” properties don’t match the order of the provided data
  • The data-date attribute and its corresponding bar element don’t align with the corresponding value on the x-axis.

Which implies that my scaling for my xAxis is off I guess, but I can’t find a mistake.

And for the tick problem, I have tried multiple things to costumize the ticks, including

xAxis.ticks(d3.timeYear,5)
xAxis.ticks(d3.timeYear.every(5))
xAxis.ticks(d3.timeYear.every(5).range(new Date(1950, 0, 1), new Date(2015, 0, 1)))

but nothing seems to work.

Would be extremely grateful for any help! :slight_smile:

xAxis.ticks(5)

Thanks for the answer, but I tried that before already. It just automatically sequences again and doesn’t let me customize it. I found solutions online, but for some reason they don’t work for my chart. All my x-values are Date types, so it should work with these functions. Down below I listed some sources I’ve checked out already, maybe someone can see sth I don’t.

https://devdocs.io/d3~3/svg-axes.md#ticks
https://github.com/d3/d3-axis
https://github.com/d3/d3-scale/blob/master/README.md#time_ticks
https://github.com/d3/d3-time
http://www.d3noob.org/2016/08/changing-number-of-ticks-on-axis-in.html

This is my xScale for comparison:

const xScale = d3.scaleLinear()
                 .domain([
			          d3.min(data, (d) => d[0]), 
				      d3.max(data, (d) => new Date(d[0]).setMonth(d[0].getMonth()+3))
				 ])
                 .range([padding, w-padding]);

And this is my call for the xAxis together with some things that I tried:

const xAxis = d3.axisBottom(xScale)
				.tickFormat(d3.timeFormat("%Y/%m/%d"))
				//.ticks(d3.timeYear,5)
				//.ticks(d3.timeYear.every(5))
				//.ticks(d3.timeYear.every(5).range(new Date(1950, 0, 1), new Date(2015, 0, 1)))

Happy about any advice!

How about using d3.scaleTime() instead of scaleLinear() ? Then .ticks(d3.timeYear.every(5)) should work.

1 Like

Thank you!! It was right in front of my eyes I guess. Now a last test doesn’t compute, it still doesn’t pass the test for

  • The bar elements’ “data-date” properties should match the order of the provided data

Any ideas? Because I can’t really find a way how that wouldn’t be the case. And I did it analog to the data-gdp value, which passes the test. Here is my code for the bars:

svg.selectAll("rect")
     	 .data(data)
         .enter()
         .append("rect")
         .attr("x", (d) => xScale(d[0]))
         .attr("y", (d) => yScale(d[1]))
		 .attr("width", wBar)
		 .attr("height", (d) => h-padding-yScale(d[1]))
         .attr("class", "bar")
		 .attr("data-date", (d) => d[0])
		 .attr("data-gdp", (d) => d[1])

Edit: Solved it - it didn’t accept the data-date attribute as a Date object, just as a string similar to the JSON object we started with.