Reputation: 769
I've been having a hard time getting ticks to work with something I've been playing with in D3. I'm still getting my feet wet with D3, but I've been learning it more and more. Taking an example I found online, I'm starting to turn it into something else.
The problem is, this uses an ordinal scale, and I can't find a way to set the ticks on my xaxis. I'd love to have it show ever 10th tick for example. but I haven't been able to have anything work so far.
Here's a link: http://freeptools.com/mapster/testing-funny2.php
Upvotes: 0
Views: 5545
Reputation: 27544
As you've discovered, an ordinal scale doesn't have a ticks
function to generate a set number of tick marks. Instead the axis object uses the entire set of values in the scale's domain to create the ticks.
This makes sense in the general case, since can't always interpolate between the category values of an ordinal scale. As I've described it previously
[The values for an ordinal scale] are assumed to be distinct categories, which might not have a natural order. They could be "apples", "oranges", and "bananas". There's no way to estimate a middle value ("oranges") based on the values of adjacent labels ("apples" and "bananas"), so by default all the labels are shown, even if they end up overlapping and unreadable.
That said, in many cases the categories do have a natural order (true "ordinal" data instead of pure categorical data) and it does make sense to skip labels.
To do that, you'll need to create your own function to generate the correct array of values to use (or hard code the array of labels if it will always be the same). Then use the axis object's .tickValues(array)
function to explicitly set those tick values.
For example, in the previously linked answer (which was actually a question about controlling the ticks on a linear scale), I showed how to use one of the d3 time interval range to generate the tick values.
For your case, a method to filter the domain array based on index might work:
var ticks = scale.domain().filter(function(d,i){ return !(i%10); } );
axis.tickValues( ticks );
Explanation:
scale
is your ordinal scale, calling its domain()
method with no parameters returns the array of all values. filter()
method creates a new array that consists of only the elements that return true when passed to the filter function. i%10
(i
modulo 10) returns 0 for index values that are multiples of 10.!
) of that result will return true
for multiples of 10. One last thing: since all the axis sees is the final list of values, it won't automatically change when the data does; you'll need to remember to redo the tick value calculation any time the data updates.
Upvotes: 14
Reputation: 108491
If you're looking to programmatically get the "center point" of an ordinal scale created with rangeRoundBands
, you can take each of the returned range()
values (the x starts of each band), and add 1/2 of the rangeBand()
(the width of the band):
var ordScale = d3.scale.ordinal().domain(['a','b','c']).rangeRoundBands([0, 100], .1, .1);
var rangeBand = ordScale.rangeBand();
var ticks = ordScale.range().map(function(r) {
return r + (rangeBand / 2);
});
EDIT: There are also helpers for just simply creating an Axis, if that's what you to do.
Upvotes: 3