2

I've looked at a couple of answers on here:

  1. how-to-limit-d3-svg-axis-to-integer-labels
  2. d3-tick-marks-on-integers-only

But they're not working for me.

I have an array of years, for example:

years: Array<number> = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017];
let minXAxis = Math.min(...this.years);
let maxXAxis = Math.max(...this.years);

this.xScale = d3.scaleLinear().range([this.margins.left, this.width - this.margins.right]).domain([minXAxis, maxXAxis]);

this.xAxis = svg.append("g")
  .attr("class", "axis axis-x")
  .attr("transform", `translate(0, ${this.height - this.margins.bottom})`)
  .call(d3.axisBottom(this.xScale));

Doing just this gives me the following.

pic

Then when I used .tickFormat(d3.format("d")) like so:

this.xAxis = svg.append("g")
  .attr("class", "axis axis-x")
  .attr("transform", `translate(0, ${this.height - this.margins.bottom})`)
  // set to only display ticks for digits
  .call(d3.axisBottom(this.xScale).tickFormat(d3.format("d")));

I get the following

pic 2

As you can see, it got rid of the decimal, but it still lists as duplicates, e.g 2011, 2011, ...

How do I fix this so the x axis only shows: 2010, 2011, 2012, ...?

Nayantara Jeyaraj
  • 2,624
  • 7
  • 34
  • 63
itsbavu
  • 33
  • 1
  • 6

1 Answers1

3

There is no duplicate in that axis: those are values that just seem to be the same because you got rid of the decimals.

The problem here is simple: you are using the wrong scale for the task. You should use a time scale or, if you want to treat those years as qualitative (categorical) variables, you should use an ordinal scale (like d3.scalePoint) instead.

Have in mind that a year is not a regular number: 2012 is a year, but what is 2012.2412223? If you use a linear scale you are treating those years exactly like this: pure numbers.

Therefore, the solution is just dropping the linear scale and using a time scale (or an ordinal scale).

However, if (for whatever reason) you want to stick with the linear scale and treat the years like numbers (which they are not), use tickValues to make sure that only the values in the years array will show up in the axis:

d3.axisBottom(this.xScale)
    .tickValues(years)

Here is a demo:

var years = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017];
var svg = d3.select("svg");
var scale = d3.scaleLinear()
  .domain(d3.extent(years))
  .range([20, 480]);
var axis = d3.axisBottom(scale)
  .tickValues(years)
  .tickFormat(d3.format("d"));
var gX = svg.append("g")
  .attr("transform", "translate(0,50)");
axis(gX);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="100"></svg>
Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • Your suggestion for tickValues() worked. I tried scaleTime() but it didn't work. Maybe I did it wrong? Also, your example doesn't work, I get unmatched parameters or something for the domain() call – itsbavu Aug 16 '17 at 03:25
  • @itsbavu You should try the time scale... the problem, however, is that it's not simply a matter of changing the scale, it involves a lot more, like parsing the dates for instance. – Gerardo Furtado Aug 16 '17 at 03:31
  • Can you update your answer with an example of that? I tried d3.timeParse("%Y"), but it's looking for a string, whereas I just have an array of numbers representing the years. – itsbavu Aug 18 '17 at 05:04
  • Since this is a different issue, I suggest you post *another* question. – Gerardo Furtado Aug 18 '17 at 05:27