kPow989
kPow989

Reputation: 426

D3 Text label for y axis in version 4

Hi I'm trying to set an ordinal scale for a line graph in d3 using v4. For some reason the ticks do not scale properly although I have scaled them as such:

var yTicks = d3.scaleOrdinal()
.domain(["apple", "orange", "banana", "grapefruit", "mango"])
.range([0, h])

var xAxis = d3.axisBottom().scale(x).tickSize(-h);

// var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(true);
var yAxisLeft = d3.axisLeft().scale(yTicks);
// Add the x-axis.
graph.append("svg:g").attr("class", "x axis").attr("transform", "translate(0," + h + ")").call(xAxis);



// add lines
 // do this AFTER the axes above so that the line is above the tick-lines
for (var i = data.length - 1; i >= 0; i--) {
    graph.append("svg:path").attr("d", line(data[i])).attr("class", "data" + (i + 1));
};        

graph.append("svg:g").attr("class", "y axis").attr("transform", "translate(0,0)").call(yAxisLeft);

The full version of what I've done can be found at this fiddle here: https://jsfiddle.net/5g1fe6qd/

Upvotes: 0

Views: 1045

Answers (2)

Andrew Reid
Andrew Reid

Reputation: 38201

This is expected behavior:

ordinal.range([range])

If range is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in range, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. If range is not specified, this method returns the current range.

(emphasis mine, from API documentation)

You've only specified two elements in your range, therefore, the five values in your domain are mapped to these two values in the range (hence the overlapping text). You could use something along these lines:

  d3.scaleOrdinal()  
    .domain(["apple", "orange", "banana", "grapefruit", "mango"])
    .range([0, h*0.25, h*0.5, h*0.75, h]

(fiddle: https://jsfiddle.net/bmysrmcd/)

However, Gerardo's answer provides an alternative that doesn't require you set map each element in the domain to the range, and that is a better solution.

Upvotes: 1

Gerardo Furtado
Gerardo Furtado

Reputation: 102198

You cannot set the range of an ordinal scale the way you did here: you have to specify the discrete values.

An easy solution in using a point scale instead:

var yTicks = d3.scalePoint()

Here is your updated fiddle: https://jsfiddle.net/5g1fe6qd/1/

Upvotes: 2

Related Questions