NewToJS
NewToJS

Reputation: 2101

D3: Formating years with the .tickValues() method

I'm trying to write a function for the .tickValues method on my X axis so that the first year in my array of data is written as the full year (2000) and the rest of the years are written as: '01, '02, '03..ect

here are the scale, axis and data:

var xScale = d3.time.scale()
.range([0, width])
.domain(d3.extent(dataset, function(d) { return d.year }));

var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");

var dataset = [
{ year: "2000", age1: 31, age2: 10, age3: 32, age4: 27 },
{ year: "2001", age1: 32, age2: 12, age3: 30, age4: 26 },
{ year: "2002", age1: 24, age2: 19, age3: 32, age4: 25 },
{ year: "2003", age1: 26, age2: 18, age3: 31, age4: 25 },
{ year: "2004", age1: 22, age2: 17, age3: 34, age4: 27 },
{ year: "2004", age1: 24, age2: 17, age3: 33, age4: 26 },
{ year: "2006", age1: 31, age2: 15, age3: 32, age4: 22 },
{ year: "2007", age1: 30, age2: 15, age3: 35, age4: 20 },
{ year: "2008", age1: 27, age2: 18, age3: 31, age4: 24 },
{ year: "2009", age1: 25, age2: 15, age3: 35, age4: 25 },
{ year: "2010", age1: 34, age2: 12, age3: 33, age4: 21 },
{ year: "2011", age1: 31, age2: 14, age3: 32, age4: 23 },
{ year: "2012", age1: 27, age2: 18, age3: 30, age4: 25 },
{ year: "2013", age1: 25, age2: 20, age3: 35, age4: 20 }
];

// convert years to dates
var parseDate = d3.time.format("%Y").parse;

dataset.forEach(function(d) {
    d.year = parseDate(d.year);
}); 

I have a function to format the years as '01, '02 ect:

 var formatYear = d3.time.format("'" +"%y");

But when I apply to it my function in the .tickValues() method it does not work:

xAxis.tickValues( function(d){ if(d==dataset[0].year){return d;}else{return formatYear(d);} } );

Upvotes: 0

Views: 209

Answers (1)

jshanley
jshanley

Reputation: 9138

The .tickValues() method is used for assigning which values receive ticks on the axis, not for assigning how they are formatted. For that, you should use the .tickFormat() method.

To start, it looks like your are doing things precisely backwards in the code block you posted. You should define your data and convert your values into dates before you create the domain of your scale.

Since you are turning the year values in your data into Date objects, when you create your scale, you can use the unary + operator to coerce them into the number of ms...

var xScale = d3.time.scale()
  .range([0, width])
  .domain(d3.extent(dataset, function(d) { return +d.year; }));

...which you can then use within the function you pass to .tickFormat():

var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(d) {
  // if the year ends in 00 then display the full year
  if (d3.time.format('%Y')(d).slice(-2) === '00') {
    return d3.time.format('%Y')(d);
  } else {
    // otherwise shorten it to the final 2 digits
    return d3.time.format('\'%y')(d);
  }
})
.ticks(d3.time.year, 1);

The last line there shows the advantage of using the actual date objects rather than the year string for the scale, as you can have precise control of the time-interval of your ticks. In this case I have specified that there should be a tick for every year.

Here is a demo JSFiddle

Upvotes: 0

Related Questions