I feel like this may be simply me misunderstanding how logarithmic scales work, but I can't seem to get D3 log scale bases to work.
In this fiddle, I attempt to create three scales with the same set of base10 ticks, with a base10 log scale, a base4 log scale, and a base2 log scale. According to my layperson understanding of logarithmic scales, the base10 log scale looks correct — the powers of ten are equidistantly spaced on the axis. But, the base4 and base2 scales are identical — it seems to me that the labels should compress to the right on those two scales. What's going on?
Fiddly code:
ticks = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]
elems = { ten: 10, four: 4, two: 2 }
for selector, base of elems
dom = d3.select('.scale.' + selector)
scale = (new d3.scale.log()).base(base).domain([ 0.5, 10000000 ]).range([ 0, 500 ])
dom.selectAll('div')
.data(ticks)
.enter().append('div')
.text((x) -> x)
.style('left', (x) -> scale(x) + 'px')
The base() method is a bit of a misnomer, IMO. It is actually a displayBase method, in that it only updates the positioning and label of the ticks.
Scales use the domain and range settings to do their magic. This is a nicely consistent way of doing things across many different scales, but with logs it is a little unintuitive.
The awkward way: In your case, modify the upper value of the domain array. For example, if the range is [0, 1000], then the domain should be [1, 3] for log-base10, and [0, 9.9658 (approx)] for log-base2. In general, top domain value is the log(base-x) of the top range value. Ditto with the bottom range value if it is higher than 0.
The simpler way: Leave the range as [0,1]. Then you can set the domain as [1, base]. The scale takes care of interpolation outside the range values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With