BrenBarn
BrenBarn

Reputation: 251398

Give d3 ordinal axis labels different from scale names

I have an ordinal scale with certain labels for the different values. I want to display an axis for that scale, where the axis labels are not the same as the scale labels. I have this code:

var width = 1000
var height = 600
var margins = {
left: 100, // 40
right: 25,
bottom: 50,
top: 0
}

var y = d3.scale.ordinal().domain(["This", "That", "Other"]).rangePoints([margins.top, height-margins.bottom], 1);

var svg = d3.select("#plot").append("svg").attr("width",width).attr("height",height)

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left")
  .tickValues(["This is long", "That is long", "Other is long"])

svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(" + margins.left + ",0)")
  .classed("yaxis", true)
  .call(yAxis);

This used to work, but apparently there has been some change in d3 in the last few months that causes it to no longer work. (This other question also says I should be able to use tickValues this way.) The tick labels do not appear. I get an error in the JavaScript console saying:

Unexpected value translate(0,NaN) parsing transform attribute. @ http://d3js.org/d3.v3.js:596

Tracing through the code, it appears that d3 is trying to call the scale on each tick value; that is, it is calling y("This is long"), which results in NaN because "This is long" is not in the scale. I don't know why it's doing this.

Here is a fiddle showing the problem. If you comment out the .tickValues line, the axis labels show up correctly. With that line uncommented, the labels don't work.

What is the way to set tick labels for an ordinal axis in d3?

Upvotes: 5

Views: 4688

Answers (1)

BrenBarn
BrenBarn

Reputation: 251398

After fiddling around a bit more I found the answer. It seems that now you must use the tickFormat function to define how an axis displays its ticks. The solution is to replace the .tickValues line with this:

.tickFormat(function (d) {
  var mapper = {
    "This": "This is long",
    "That": "That is long",
    "Other": "Other is long"
  }
  return mapper[d]
})

The documentation does not make this clear; it only explicitly discusses "number formatters". It does not make the API of a "formatter" clear. It seems that a formatter takes a single value from a scale as input and is supposed to return the display version of that value. For ordinal scales, though, that value may not be a number but a named value on the scale.

Upvotes: 21

Related Questions